feat: restore page version

This commit is contained in:
NGPixel 2020-02-29 23:40:07 -05:00 committed by Nicolas Giard
parent e50dc89519
commit e85de92715
5 changed files with 125 additions and 8 deletions

View File

@ -55,7 +55,7 @@
v-list-item(@click='download(ph.versionId)') v-list-item(@click='download(ph.versionId)')
v-list-item-avatar(size='24'): v-icon mdi-cloud-download-outline v-list-item-avatar(size='24'): v-icon mdi-cloud-download-outline
v-list-item-title Download Version v-list-item-title Download Version
v-list-item(@click='restore(ph.versionId)', :disabled='ph.versionId === 0') v-list-item(@click='restore(ph.versionId, ph.versionDate)', :disabled='ph.versionId === 0')
v-list-item-avatar(size='24'): v-icon(:disabled='ph.versionId === 0') mdi-history v-list-item-avatar(size='24'): v-icon(:disabled='ph.versionId === 0') mdi-history
v-list-item-title Restore v-list-item-title Restore
v-list-item(@click='branchOff(ph.versionId)') v-list-item(@click='branchOff(ph.versionId)')
@ -111,6 +111,17 @@
.overline View Mode .overline View Mode
v-card.mt-3(light, v-html='diffHTML', flat) v-card.mt-3(light, v-html='diffHTML', flat)
v-dialog(v-model='isRestoreConfirmDialogShown', max-width='650', persistent)
v-card
.dialog-header.is-orange {{$t('history:restore.confirmTitle')}}
v-card-text.pa-4
i18next(tag='span', path='history:restore.confirmText')
strong(place='date') {{ restoreTarget.versionDate | moment('LLL') }}
v-card-actions
v-spacer
v-btn(text, @click='isRestoreConfirmDialogShown = false', :disabled='restoreLoading') {{$t('common:actions.cancel')}}
v-btn(color='orange darken-2', dark, @click='restoreConfirm', :loading='restoreLoading') {{$t('history:restore.confirmButton')}}
nav-footer nav-footer
notify notify
search-results search-results
@ -124,6 +135,7 @@ import _ from 'lodash'
import gql from 'graphql-tag' import gql from 'graphql-tag'
export default { export default {
i18nOptions: { namespaces: 'history' },
props: { props: {
pageId: { pageId: {
type: Number, type: Number,
@ -194,7 +206,13 @@ export default {
offsetPage: 0, offsetPage: 0,
total: 0, total: 0,
viewMode: 'line-by-line', viewMode: 'line-by-line',
cache: [] cache: [],
restoreTarget: {
versionId: 0,
versionDate: ''
},
isRestoreConfirmDialogShown: false,
restoreLoading: false
} }
}, },
computed: { computed: {
@ -335,8 +353,59 @@ export default {
download (versionId) { download (versionId) {
window.location.assign(`/d/${this.locale}/${this.path}?v=${versionId}`) window.location.assign(`/d/${this.locale}/${this.path}?v=${versionId}`)
}, },
restore (versionId) { restore (versionId, versionDate) {
this.restoreTarget = {
versionId,
versionDate
}
this.isRestoreConfirmDialogShown = true
},
async restoreConfirm () {
this.restoreLoading = true
this.$store.commit(`loadingStart`, 'history-restore')
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation ($pageId: Int!, $versionId: Int!) {
pages {
restore (pageId: $pageId, versionId: $versionId) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
versionId: this.restoreTarget.versionId,
pageId: this.pageId
}
})
if (_.get(resp, 'data.pages.restore.responseResult.succeeded', false) === true) {
this.$store.commit('showNotification', {
style: 'success',
message: this.$t('history:restore.success'),
icon: 'check'
})
this.isRestoreConfirmDialogShown = false
setTimeout(() => {
window.location.assign(`/${this.locale}/${this.path}`)
}, 1000)
} else {
throw new Error(_.get(resp, 'data.pages.restore.responseResult.message', 'An unexpected error occured'))
}
} catch (err) {
this.$store.commit('showNotification', {
style: 'red',
message: err.message,
icon: 'alert'
})
}
this.$store.commit(`loadingStop`, 'history-restore')
this.restoreLoading = false
}, },
branchOff (versionId) { branchOff (versionId) {

View File

@ -385,7 +385,7 @@ module.exports = {
try { try {
const page = await WIKI.models.pages.query().findById(args.id) const page = await WIKI.models.pages.query().findById(args.id)
if (!page) { if (!page) {
throw new Error('Invalid Page Id') throw new WIKI.Error.PageNotFound()
} }
await WIKI.models.pages.renderPage(page) await WIKI.models.pages.renderPage(page)
return { return {
@ -394,6 +394,42 @@ module.exports = {
} catch (err) { } catch (err) {
return graphHelper.generateError(err) return graphHelper.generateError(err)
} }
},
/**
* RESTORE PAGE VERSION
*/
async restore (obj, args, context) {
try {
const page = await WIKI.models.pages.query().select('path', 'localeCode').findById(args.pageId)
if (!page) {
throw new WIKI.Error.PageNotFound()
}
if (!WIKI.auth.checkAccess(context.req.user, ['write:pages'], {
path: page.path,
locale: page.localeCode
})) {
throw new WIKI.Error.PageRestoreForbidden()
}
const targetVersion = await WIKI.models.pageHistory.getVersion({ pageId: args.pageId, versionId: args.versionId })
if (!targetVersion) {
throw new WIKI.Error.PageNotFound()
}
await WIKI.models.pages.updatePage({
...targetVersion,
id: targetVersion.pageId,
user: context.req.user,
action: 'restored'
})
return {
responseResult: graphHelper.generateSuccess('Page version restored successfully.')
}
} catch (err) {
return graphHelper.generateError(err)
}
} }
}, },
Page: { Page: {

View File

@ -129,6 +129,11 @@ type PageMutation {
render( render(
id: Int! id: Int!
): DefaultResponse @auth(requires: ["manage:system"]) ): DefaultResponse @auth(requires: ["manage:system"])
restore(
pageId: Int!
versionId: Int!
): DefaultResponse @auth(requires: ["write:pages", "manage:pages", "manage:system"])
} }
# ----------------------------------------------- # -----------------------------------------------

View File

@ -153,6 +153,10 @@ module.exports = {
message: 'Destination page path already exists.', message: 'Destination page path already exists.',
code: 6006 code: 6006
}), }),
PageRestoreForbidden: CustomError('PageRestoreForbidden', {
message: 'You are not authorized to restore this page version.',
code: 6011
}),
PageUpdateForbidden: CustomError('PageUpdateForbidden', { PageUpdateForbidden: CustomError('PageUpdateForbidden', {
message: 'You are not authorized to update this page.', message: 'You are not authorized to update this page.',
code: 6009 code: 6009

View File

@ -326,7 +326,8 @@ module.exports = class Page extends Model {
await WIKI.models.pageHistory.addVersion({ await WIKI.models.pageHistory.addVersion({
...ogPage, ...ogPage,
isPublished: ogPage.isPublished === true || ogPage.isPublished === 1, isPublished: ogPage.isPublished === true || ogPage.isPublished === 1,
action: 'updated' action: opts.action ? opts.action : 'updated',
versionDate: ogPage.updatedAt
}) })
// -> Update page // -> Update page
@ -422,7 +423,8 @@ module.exports = class Page extends Model {
// -> Create version snapshot // -> Create version snapshot
await WIKI.models.pageHistory.addVersion({ await WIKI.models.pageHistory.addVersion({
...page, ...page,
action: 'moved' action: 'moved',
versionDate: page.updatedAt
}) })
const destinationHash = pageHelper.generateHash({ path: opts.destinationPath, locale: opts.destinationLocale, privateNS: opts.isPrivate ? 'TODO' : '' }) const destinationHash = pageHelper.generateHash({ path: opts.destinationPath, locale: opts.destinationLocale, privateNS: opts.isPrivate ? 'TODO' : '' })
@ -503,7 +505,8 @@ module.exports = class Page extends Model {
// -> Create version snapshot // -> Create version snapshot
await WIKI.models.pageHistory.addVersion({ await WIKI.models.pageHistory.addVersion({
...page, ...page,
action: 'deleted' action: 'deleted',
versionDate: page.updatedAt
}) })
// -> Delete page // -> Delete page