feat: convert page
This commit is contained in:
		| @@ -150,6 +150,9 @@ | |||||||
|                 v-list-item.pl-4(@click='pageSource', v-if='mode !== `source` && hasReadSourcePermission') |                 v-list-item.pl-4(@click='pageSource', v-if='mode !== `source` && hasReadSourcePermission') | ||||||
|                   v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-code-tags |                   v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-code-tags | ||||||
|                   v-list-item-title.body-2 {{$t('common:header.viewSource')}} |                   v-list-item-title.body-2 {{$t('common:header.viewSource')}} | ||||||
|  |                 v-list-item.pl-4(@click='pageConvert', v-if='hasWritePagesPermission') | ||||||
|  |                   v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-lightning-bolt | ||||||
|  |                   v-list-item-title.body-2 {{$t('common:header.convert')}} | ||||||
|                 v-list-item.pl-4(@click='pageDuplicate', v-if='hasWritePagesPermission') |                 v-list-item.pl-4(@click='pageDuplicate', v-if='hasWritePagesPermission') | ||||||
|                   v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-content-duplicate |                   v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-content-duplicate | ||||||
|                   v-list-item-title.body-2 {{$t('common:header.duplicate')}} |                   v-list-item-title.body-2 {{$t('common:header.duplicate')}} | ||||||
| @@ -237,6 +240,7 @@ | |||||||
|     page-selector(mode='move', v-model='movePageModal', :open-handler='pageMoveRename', :path='path', :locale='locale') |     page-selector(mode='move', v-model='movePageModal', :open-handler='pageMoveRename', :path='path', :locale='locale') | ||||||
|     page-selector(mode='create', v-model='duplicateOpts.modal', :open-handler='pageDuplicateHandle', :path='duplicateOpts.path', :locale='duplicateOpts.locale') |     page-selector(mode='create', v-model='duplicateOpts.modal', :open-handler='pageDuplicateHandle', :path='duplicateOpts.path', :locale='duplicateOpts.locale') | ||||||
|     page-delete(v-model='deletePageModal', v-if='path && path.length') |     page-delete(v-model='deletePageModal', v-if='path && path.length') | ||||||
|  |     page-convert(v-model='convertPageModal', v-if='path && path.length') | ||||||
|  |  | ||||||
|     .nav-header-dev(v-if='isDevMode') |     .nav-header-dev(v-if='isDevMode') | ||||||
|       v-icon mdi-alert |       v-icon mdi-alert | ||||||
| @@ -255,7 +259,8 @@ import movePageMutation from 'gql/common/common-pages-mutation-move.gql' | |||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   components: { |   components: { | ||||||
|     PageDelete: () => import('./page-delete.vue') |     PageDelete: () => import('./page-delete.vue'), | ||||||
|  |     PageConvert: () => import('./page-convert.vue') | ||||||
|   }, |   }, | ||||||
|   props: { |   props: { | ||||||
|     dense: { |     dense: { | ||||||
| @@ -274,6 +279,7 @@ export default { | |||||||
|       searchAdvMenuShown: false, |       searchAdvMenuShown: false, | ||||||
|       newPageModal: false, |       newPageModal: false, | ||||||
|       movePageModal: false, |       movePageModal: false, | ||||||
|  |       convertPageModal: false, | ||||||
|       deletePageModal: false, |       deletePageModal: false, | ||||||
|       locales: siteLangs, |       locales: siteLangs, | ||||||
|       isDevMode: false, |       isDevMode: false, | ||||||
| @@ -354,6 +360,9 @@ export default { | |||||||
|     this.$root.$on('pageMove', () => { |     this.$root.$on('pageMove', () => { | ||||||
|       this.pageMove() |       this.pageMove() | ||||||
|     }) |     }) | ||||||
|  |     this.$root.$on('pageConvert', () => { | ||||||
|  |       this.pageConvert() | ||||||
|  |     }) | ||||||
|     this.$root.$on('pageDuplicate', () => { |     this.$root.$on('pageDuplicate', () => { | ||||||
|       this.pageDuplicate() |       this.pageDuplicate() | ||||||
|     }) |     }) | ||||||
| @@ -416,6 +425,9 @@ export default { | |||||||
|     pageDuplicateHandle ({ locale, path }) { |     pageDuplicateHandle ({ locale, path }) { | ||||||
|       window.location.assign(`/e/${locale}/${path}?from=${this.$store.get('page/id')}`) |       window.location.assign(`/e/${locale}/${path}?from=${this.$store.get('page/id')}`) | ||||||
|     }, |     }, | ||||||
|  |     pageConvert () { | ||||||
|  |       this.convertPageModal = true | ||||||
|  |     }, | ||||||
|     pageMove () { |     pageMove () { | ||||||
|       this.movePageModal = true |       this.movePageModal = true | ||||||
|     }, |     }, | ||||||
|   | |||||||
							
								
								
									
										122
									
								
								client/components/common/page-convert.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								client/components/common/page-convert.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | |||||||
|  | <template lang='pug'> | ||||||
|  |   v-dialog( | ||||||
|  |     v-model='isShown' | ||||||
|  |     max-width='550' | ||||||
|  |     persistent | ||||||
|  |     overlay-color='blue-grey darken-4' | ||||||
|  |     overlay-opacity='.7' | ||||||
|  |     ) | ||||||
|  |     v-card | ||||||
|  |       .dialog-header.is-short.is-dark | ||||||
|  |         v-icon.mr-2(color='white') mdi-lightning-bolt | ||||||
|  |         span {{$t('common:page.convert')}} | ||||||
|  |       v-card-text.pt-5 | ||||||
|  |         i18next.body-2(path='common:page.convertTitle', tag='div') | ||||||
|  |           span.blue-grey--text.text--darken-2(place='title') {{pageTitle}} | ||||||
|  |         v-select.mt-5( | ||||||
|  |           :items=`[ | ||||||
|  |             { value: 'markdown', text: 'Markdown' }, | ||||||
|  |             { value: 'ckeditor', text: 'Visual Editor' }, | ||||||
|  |             { value: 'code', text: 'Raw HTML' } | ||||||
|  |           ]` | ||||||
|  |           outlined | ||||||
|  |           dense | ||||||
|  |           hide-details | ||||||
|  |           v-model='newEditor' | ||||||
|  |         ) | ||||||
|  |         .caption.mt-5 {{$t('common:page.convertSubtitle')}} | ||||||
|  |       v-card-chin | ||||||
|  |         v-spacer | ||||||
|  |         v-btn(text, @click='discard', :disabled='loading') {{$t('common:actions.cancel')}} | ||||||
|  |         v-btn.px-4(color='grey darken-3', @click='convertPage', :loading='loading').white--text {{$t('common:actions.convert')}} | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import _ from 'lodash' | ||||||
|  | import { get } from 'vuex-pathify' | ||||||
|  | import gql from 'graphql-tag' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   props: { | ||||||
|  |     value: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: false | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       loading: false, | ||||||
|  |       newEditor: '' | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     isShown: { | ||||||
|  |       get() { return this.value }, | ||||||
|  |       set(val) { this.$emit('input', val) } | ||||||
|  |     }, | ||||||
|  |     pageTitle: get('page/title'), | ||||||
|  |     pagePath: get('page/path'), | ||||||
|  |     pageLocale: get('page/locale'), | ||||||
|  |     pageId: get('page/id'), | ||||||
|  |     pageEditor: get('page/editor') | ||||||
|  |   }, | ||||||
|  |   mounted () { | ||||||
|  |     this.newEditor = this.pageEditor | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     discard() { | ||||||
|  |       this.isShown = false | ||||||
|  |     }, | ||||||
|  |     async convertPage() { | ||||||
|  |       this.loading = true | ||||||
|  |       this.$store.commit(`loadingStart`, 'page-convert') | ||||||
|  |       this.$nextTick(async () => { | ||||||
|  |         try { | ||||||
|  |           const resp = await this.$apollo.mutate({ | ||||||
|  |             mutation: gql` | ||||||
|  |               mutation ( | ||||||
|  |                 $id: Int! | ||||||
|  |                 $editor: String! | ||||||
|  |                 ) { | ||||||
|  |                   pages { | ||||||
|  |                     convert( | ||||||
|  |                       id: $id | ||||||
|  |                       editor: $editor | ||||||
|  |                     ) { | ||||||
|  |                       responseResult { | ||||||
|  |                         succeeded | ||||||
|  |                         errorCode | ||||||
|  |                         slug | ||||||
|  |                         message | ||||||
|  |                       } | ||||||
|  |                     } | ||||||
|  |                   } | ||||||
|  |               } | ||||||
|  |             `, | ||||||
|  |             variables: { | ||||||
|  |               id: this.pageId, | ||||||
|  |               editor: this.newEditor | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |           if (_.get(resp, 'data.pages.convert.responseResult.succeeded', false)) { | ||||||
|  |             this.isShown = false | ||||||
|  |             _.delay(() => { | ||||||
|  |               window.location.assign(`/e/${this.pageLocale}/${this.pagePath}`) | ||||||
|  |             }, 400) | ||||||
|  |           } else { | ||||||
|  |             throw new Error(_.get(resp, 'data.pages.convert.responseResult.message', this.$t('common:error.unexpected'))) | ||||||
|  |           } | ||||||
|  |         } catch (err) { | ||||||
|  |           this.$store.commit('pushGraphError', err) | ||||||
|  |         } | ||||||
|  |         this.$store.commit(`loadingStop`, 'page-convert') | ||||||
|  |         this.loading = false | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang='scss'> | ||||||
|  |  | ||||||
|  | </style> | ||||||
| @@ -14,6 +14,7 @@ const state = { | |||||||
|   tags: [], |   tags: [], | ||||||
|   title: '', |   title: '', | ||||||
|   updatedAt: '', |   updatedAt: '', | ||||||
|  |   editor: '', | ||||||
|   mode: '', |   mode: '', | ||||||
|   scriptJs: '', |   scriptJs: '', | ||||||
|   scriptCss: '', |   scriptCss: '', | ||||||
|   | |||||||
| @@ -234,6 +234,18 @@ | |||||||
|                         ) |                         ) | ||||||
|                         v-icon(size='20') mdi-code-tags |                         v-icon(size='20') mdi-code-tags | ||||||
|                     span {{$t('common:header.viewSource')}} |                     span {{$t('common:header.viewSource')}} | ||||||
|  |                   v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasWritePagesPermission') | ||||||
|  |                     template(v-slot:activator='{ on }') | ||||||
|  |                       v-btn( | ||||||
|  |                         fab | ||||||
|  |                         small | ||||||
|  |                         color='white' | ||||||
|  |                         light | ||||||
|  |                         v-on='on' | ||||||
|  |                         @click='pageConvert' | ||||||
|  |                         ) | ||||||
|  |                         v-icon(size='20') mdi-lightning-bolt | ||||||
|  |                     span {{$t('common:header.convert')}} | ||||||
|                   v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasWritePagesPermission') |                   v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasWritePagesPermission') | ||||||
|                     template(v-slot:activator='{ on }') |                     template(v-slot:activator='{ on }') | ||||||
|                       v-btn( |                       v-btn( | ||||||
| @@ -314,7 +326,7 @@ import _ from 'lodash' | |||||||
| import ClipboardJS from 'clipboard' | import ClipboardJS from 'clipboard' | ||||||
| import Vue from 'vue' | import Vue from 'vue' | ||||||
|  |  | ||||||
| Vue.component('tabset', Tabset) | Vue.component('Tabset', Tabset) | ||||||
|  |  | ||||||
| Prism.plugins.autoloader.languages_path = '/_assets/js/prism/' | Prism.plugins.autoloader.languages_path = '/_assets/js/prism/' | ||||||
| Prism.plugins.NormalizeWhitespace.setDefaults({ | Prism.plugins.NormalizeWhitespace.setDefaults({ | ||||||
| @@ -397,6 +409,10 @@ export default { | |||||||
|       type: Number, |       type: Number, | ||||||
|       default: 0 |       default: 0 | ||||||
|     }, |     }, | ||||||
|  |     editor: { | ||||||
|  |       type: String, | ||||||
|  |       default: '' | ||||||
|  |     }, | ||||||
|     isPublished: { |     isPublished: { | ||||||
|       type: Boolean, |       type: Boolean, | ||||||
|       default: false |       default: false | ||||||
| @@ -516,6 +532,7 @@ export default { | |||||||
|     this.$store.set('page/path', this.path) |     this.$store.set('page/path', this.path) | ||||||
|     this.$store.set('page/tags', this.tags) |     this.$store.set('page/tags', this.tags) | ||||||
|     this.$store.set('page/title', this.title) |     this.$store.set('page/title', this.title) | ||||||
|  |     this.$store.set('page/editor', this.editor) | ||||||
|     this.$store.set('page/updatedAt', this.updatedAt) |     this.$store.set('page/updatedAt', this.updatedAt) | ||||||
|     if (this.effectivePermissions) { |     if (this.effectivePermissions) { | ||||||
|       this.$store.set('page/effectivePermissions', JSON.parse(Buffer.from(this.effectivePermissions, 'base64').toString())) |       this.$store.set('page/effectivePermissions', JSON.parse(Buffer.from(this.effectivePermissions, 'base64').toString())) | ||||||
| @@ -597,6 +614,9 @@ export default { | |||||||
|     pageSource () { |     pageSource () { | ||||||
|       this.$root.$emit('pageSource') |       this.$root.$emit('pageSource') | ||||||
|     }, |     }, | ||||||
|  |     pageConvert () { | ||||||
|  |       this.$root.$emit('pageConvert') | ||||||
|  |     }, | ||||||
|     pageDuplicate () { |     pageDuplicate () { | ||||||
|       this.$root.$emit('pageDuplicate') |       this.$root.$emit('pageDuplicate') | ||||||
|     }, |     }, | ||||||
|   | |||||||
| @@ -39,6 +39,7 @@ | |||||||
|     "@aoberoi/passport-slack": "1.0.5", |     "@aoberoi/passport-slack": "1.0.5", | ||||||
|     "@azure/storage-blob": "12.2.1", |     "@azure/storage-blob": "12.2.1", | ||||||
|     "@exlinc/keycloak-passport": "1.0.2", |     "@exlinc/keycloak-passport": "1.0.2", | ||||||
|  |     "@joplin/turndown-plugin-gfm": "1.0.27", | ||||||
|     "@root/csr": "0.8.1", |     "@root/csr": "0.8.1", | ||||||
|     "@root/keypairs": "0.10.1", |     "@root/keypairs": "0.10.1", | ||||||
|     "@root/pem": "1.0.4", |     "@root/pem": "1.0.4", | ||||||
| @@ -176,6 +177,7 @@ | |||||||
|     "striptags": "3.1.1", |     "striptags": "3.1.1", | ||||||
|     "subscriptions-transport-ws": "0.9.18", |     "subscriptions-transport-ws": "0.9.18", | ||||||
|     "tar-fs": "2.1.0", |     "tar-fs": "2.1.0", | ||||||
|  |     "turndown": "7.0.0", | ||||||
|     "twemoji": "13.0.1", |     "twemoji": "13.0.1", | ||||||
|     "uslug": "1.0.4", |     "uslug": "1.0.4", | ||||||
|     "uuid": "8.3.1", |     "uuid": "8.3.1", | ||||||
|   | |||||||
| @@ -398,6 +398,22 @@ module.exports = { | |||||||
|         return graphHelper.generateError(err) |         return graphHelper.generateError(err) | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     /** | ||||||
|  |      * CONVERT PAGE | ||||||
|  |      */ | ||||||
|  |     async convert(obj, args, context) { | ||||||
|  |       try { | ||||||
|  |         await WIKI.models.pages.convertPage({ | ||||||
|  |           ...args, | ||||||
|  |           user: context.req.user | ||||||
|  |         }) | ||||||
|  |         return { | ||||||
|  |           responseResult: graphHelper.generateSuccess('Page has been converted.') | ||||||
|  |         } | ||||||
|  |       } catch (err) { | ||||||
|  |         return graphHelper.generateError(err) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     /** |     /** | ||||||
|      * MOVE PAGE |      * MOVE PAGE | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -112,6 +112,11 @@ type PageMutation { | |||||||
|     title: String |     title: String | ||||||
|   ): PageResponse @auth(requires: ["write:pages", "manage:pages", "manage:system"]) |   ): PageResponse @auth(requires: ["write:pages", "manage:pages", "manage:system"]) | ||||||
|  |  | ||||||
|  |   convert( | ||||||
|  |     id: Int! | ||||||
|  |     editor: String! | ||||||
|  |   ): DefaultResponse @auth(requires: ["write:pages", "manage:pages", "manage:system"]) | ||||||
|  |  | ||||||
|   move( |   move( | ||||||
|     id: Int! |     id: Int! | ||||||
|     destinationPath: String! |     destinationPath: String! | ||||||
|   | |||||||
| @@ -9,6 +9,9 @@ const striptags = require('striptags') | |||||||
| const emojiRegex = require('emoji-regex') | const emojiRegex = require('emoji-regex') | ||||||
| const he = require('he') | const he = require('he') | ||||||
| const CleanCSS = require('clean-css') | const CleanCSS = require('clean-css') | ||||||
|  | const TurndownService = require('turndown') | ||||||
|  | const turndownPluginGfm = require('@joplin/turndown-plugin-gfm').gfm | ||||||
|  | const cheerio = require('cheerio') | ||||||
|  |  | ||||||
| /* global WIKI */ | /* global WIKI */ | ||||||
|  |  | ||||||
| @@ -140,6 +143,7 @@ module.exports = class Page extends Model { | |||||||
|       creatorId: 'uint', |       creatorId: 'uint', | ||||||
|       creatorName: 'string', |       creatorName: 'string', | ||||||
|       description: 'string', |       description: 'string', | ||||||
|  |       editorKey: 'string', | ||||||
|       isPrivate: 'boolean', |       isPrivate: 'boolean', | ||||||
|       isPublished: 'boolean', |       isPublished: 'boolean', | ||||||
|       publishEndDate: 'string', |       publishEndDate: 'string', | ||||||
| @@ -471,6 +475,134 @@ module.exports = class Page extends Model { | |||||||
|     return page |     return page | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Convert an Existing Page | ||||||
|  |    * | ||||||
|  |    * @param {Object} opts Page Properties | ||||||
|  |    * @returns {Promise} Promise of the Page Model Instance | ||||||
|  |    */ | ||||||
|  |   static async convertPage(opts) { | ||||||
|  |     // -> Fetch original page | ||||||
|  |     const ogPage = await WIKI.models.pages.query().findById(opts.id) | ||||||
|  |     if (!ogPage) { | ||||||
|  |       throw new Error('Invalid Page Id') | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // -> Check for page access | ||||||
|  |     if (!WIKI.auth.checkAccess(opts.user, ['write:pages'], { | ||||||
|  |       locale: ogPage.localeCode, | ||||||
|  |       path: ogPage.path | ||||||
|  |     })) { | ||||||
|  |       throw new WIKI.Error.PageUpdateForbidden() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // -> Check content type | ||||||
|  |     const sourceContentType = ogPage.contentType | ||||||
|  |     const targetContentType = _.get(_.find(WIKI.data.editors, ['key', opts.editor]), `contentType`, 'text') | ||||||
|  |     const shouldConvert = sourceContentType !== targetContentType | ||||||
|  |     let convertedContent = null | ||||||
|  |  | ||||||
|  |     // -> Convert content | ||||||
|  |     if (shouldConvert) { | ||||||
|  |       // -> Markdown => HTML | ||||||
|  |       if (sourceContentType === 'markdown' && targetContentType === 'html') { | ||||||
|  |         if (!ogPage.render) { | ||||||
|  |           throw new Error('Aborted conversion because rendered page content is empty!') | ||||||
|  |         } | ||||||
|  |         convertedContent = ogPage.render | ||||||
|  |  | ||||||
|  |         const $ = cheerio.load(convertedContent, { | ||||||
|  |           decodeEntities: true | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |         if ($.root().children().length > 0) { | ||||||
|  |           $('.toc-anchor').remove() | ||||||
|  |  | ||||||
|  |           convertedContent = $.html('body').replace('<body>', '').replace('</body>', '').replace(/&#x([0-9a-f]{1,6});/ig, (entity, code) => { | ||||||
|  |             code = parseInt(code, 16) | ||||||
|  |  | ||||||
|  |             // Don't unescape ASCII characters, assuming they're encoded for a good reason | ||||||
|  |             if (code < 0x80) return entity | ||||||
|  |  | ||||||
|  |             return String.fromCodePoint(code) | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |       // -> HTML => Markdown | ||||||
|  |       } else if (sourceContentType === 'html' && targetContentType === 'markdown') { | ||||||
|  |         const td = new TurndownService({ | ||||||
|  |           bulletListMarker: '-', | ||||||
|  |           codeBlockStyle: 'fenced', | ||||||
|  |           emDelimiter: '*', | ||||||
|  |           fence: '```', | ||||||
|  |           headingStyle: 'atx', | ||||||
|  |           hr: '---', | ||||||
|  |           linkStyle: 'inlined', | ||||||
|  |           preformattedCode: true, | ||||||
|  |           strongDelimiter: '**' | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |         td.use(turndownPluginGfm) | ||||||
|  |  | ||||||
|  |         td.keep(['kbd']) | ||||||
|  |  | ||||||
|  |         td.addRule('subscript', { | ||||||
|  |           filter: ['sub'], | ||||||
|  |           replacement: c => `~${c}~` | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |         td.addRule('superscript', { | ||||||
|  |           filter: ['sup'], | ||||||
|  |           replacement: c => `^${c}^` | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |         td.addRule('underline', { | ||||||
|  |           filter: ['u'], | ||||||
|  |           replacement: c => `_${c}_` | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |         td.addRule('removeTocAnchors', { | ||||||
|  |           filter: (n, o) => { | ||||||
|  |             return n.nodeName === 'A' && n.classList.contains('toc-anchor') | ||||||
|  |           }, | ||||||
|  |           replacement: c => '' | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |         convertedContent = td.turndown(ogPage.content) | ||||||
|  |       // -> Unsupported | ||||||
|  |       } else { | ||||||
|  |         throw new Error('Unsupported source / destination content types combination.') | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // -> Create version snapshot | ||||||
|  |     if (shouldConvert) { | ||||||
|  |       await WIKI.models.pageHistory.addVersion({ | ||||||
|  |         ...ogPage, | ||||||
|  |         isPublished: ogPage.isPublished === true || ogPage.isPublished === 1, | ||||||
|  |         action: 'updated', | ||||||
|  |         versionDate: ogPage.updatedAt | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // -> Update page | ||||||
|  |     await WIKI.models.pages.query().patch({ | ||||||
|  |       contentType: targetContentType, | ||||||
|  |       editorKey: opts.editor, | ||||||
|  |       ...(convertedContent ? { content: convertedContent } : {}) | ||||||
|  |     }).where('id', ogPage.id) | ||||||
|  |     const page = await WIKI.models.pages.getPageFromDb(ogPage.id) | ||||||
|  |  | ||||||
|  |     await WIKI.models.pages.deletePageFromCache(page.hash) | ||||||
|  |     WIKI.events.outbound.emit('deletePageFromCache', page.hash) | ||||||
|  |  | ||||||
|  |     // -> Update on Storage | ||||||
|  |     await WIKI.models.storage.pageEvent({ | ||||||
|  |       event: 'updated', | ||||||
|  |       page | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Move a Page |    * Move a Page | ||||||
|    * |    * | ||||||
| @@ -872,6 +1004,7 @@ module.exports = class Page extends Model { | |||||||
|       creatorId: page.creatorId, |       creatorId: page.creatorId, | ||||||
|       creatorName: page.creatorName, |       creatorName: page.creatorName, | ||||||
|       description: page.description, |       description: page.description, | ||||||
|  |       editorKey: page.editorKey, | ||||||
|       extra: { |       extra: { | ||||||
|         css: _.get(page, 'extra.css', ''), |         css: _.get(page, 'extra.css', ''), | ||||||
|         js: _.get(page, 'extra.js', '') |         js: _.get(page, 'extra.js', '') | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ block body | |||||||
|       updated-at=page.updatedAt |       updated-at=page.updatedAt | ||||||
|       author-name=page.authorName |       author-name=page.authorName | ||||||
|       :author-id=page.authorId |       :author-id=page.authorId | ||||||
|  |       editor=page.editorKey | ||||||
|       :is-published=page.isPublished.toString() |       :is-published=page.isPublished.toString() | ||||||
|       toc=Buffer.from(page.toc).toString('base64') |       toc=Buffer.from(page.toc).toString('base64') | ||||||
|       :page-id=page.id |       :page-id=page.id | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								yarn.lock
									
									
									
									
									
								
							| @@ -3220,6 +3220,11 @@ | |||||||
|     "@types/yargs" "^15.0.0" |     "@types/yargs" "^15.0.0" | ||||||
|     chalk "^4.0.0" |     chalk "^4.0.0" | ||||||
|  |  | ||||||
|  | "@joplin/turndown-plugin-gfm@1.0.27": | ||||||
|  |   version "1.0.27" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@joplin/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.27.tgz#15ae15c169b88a355647065e7502f6619f0ace46" | ||||||
|  |   integrity sha512-4BPgTSkhvxPI3tbjG4BPiBq0VuNZji1Y77DRWHb09GnzsrgwBI+gpo3EI6obkyIeRuN/03wzf98W5u1iau2vpQ== | ||||||
|  |  | ||||||
| "@kwsites/file-exists@^1.1.1": | "@kwsites/file-exists@^1.1.1": | ||||||
|   version "1.1.1" |   version "1.1.1" | ||||||
|   resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.1.1.tgz#ad1efcac13e1987d8dbaf235ef3be5b0d96faa99" |   resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.1.1.tgz#ad1efcac13e1987d8dbaf235ef3be5b0d96faa99" | ||||||
| @@ -8277,6 +8282,11 @@ domhandler@^2.3.0: | |||||||
|   dependencies: |   dependencies: | ||||||
|     domelementtype "1" |     domelementtype "1" | ||||||
|  |  | ||||||
|  | domino@^2.1.6: | ||||||
|  |   version "2.1.6" | ||||||
|  |   resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe" | ||||||
|  |   integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ== | ||||||
|  |  | ||||||
| dompurify@2.2.0: | dompurify@2.2.0: | ||||||
|   version "2.2.0" |   version "2.2.0" | ||||||
|   resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.2.0.tgz#51d34e76faa38b5d6b4e83a0678530f27fe3965c" |   resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.2.0.tgz#51d34e76faa38b5d6b4e83a0678530f27fe3965c" | ||||||
| @@ -18405,6 +18415,13 @@ tunnel@0.0.6, tunnel@^0.0.6: | |||||||
|   resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" |   resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" | ||||||
|   integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== |   integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== | ||||||
|  |  | ||||||
|  | turndown@7.0.0: | ||||||
|  |   version "7.0.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/turndown/-/turndown-7.0.0.tgz#19b2a6a2d1d700387a1e07665414e4af4fec5225" | ||||||
|  |   integrity sha512-G1FfxfR0mUNMeGjszLYl3kxtopC4O9DRRiMlMDDVHvU1jaBkGFg4qxIyjIk2aiKLHyDyZvZyu4qBO2guuYBy3Q== | ||||||
|  |   dependencies: | ||||||
|  |     domino "^2.1.6" | ||||||
|  |  | ||||||
| tweetnacl@^0.14.3, tweetnacl@~0.14.0: | tweetnacl@^0.14.3, tweetnacl@~0.14.0: | ||||||
|   version "0.14.5" |   version "0.14.5" | ||||||
|   resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" |   resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user