fix: editing buttons showing up even if no action is allowed (#2043)

* feat: Edit / Page Create Buttons showing up even if no action is allowed #1780
This commit is contained in:
Regev Brody 2020-06-20 01:54:05 +03:00 committed by GitHub
parent b723d7d626
commit 0a16929a57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 136 additions and 41 deletions

View File

@ -156,7 +156,7 @@ export default {
}, },
computed: { computed: {
pageId: get('page/id'), pageId: get('page/id'),
permissions: get('page/commentsPermissions'), permissions: get('page/effectivePermissions@comments'),
isAuthenticated: get('user/authenticated'), isAuthenticated: get('user/authenticated'),
userDisplayName: get('user/name') userDisplayName: get('user/name')
}, },

View File

@ -111,7 +111,7 @@
//- PAGE ACTIONS //- PAGE ACTIONS
template(v-if='isAuthenticated && path && mode !== `edit`') template(v-if='hasAnyPagePermissions && path && mode !== `edit`')
v-menu(offset-y, bottom, transition='slide-y-transition', left) v-menu(offset-y, bottom, transition='slide-y-transition', left)
template(v-slot:activator='{ on: menu }') template(v-slot:activator='{ on: menu }')
v-tooltip(bottom) v-tooltip(bottom)
@ -122,33 +122,33 @@
v-list(nav, :light='!$vuetify.theme.dark', :dark='$vuetify.theme.dark', :class='$vuetify.theme.dark ? `grey darken-4` : ``') v-list(nav, :light='!$vuetify.theme.dark', :dark='$vuetify.theme.dark', :class='$vuetify.theme.dark ? `grey darken-4` : ``')
.overline.pa-4.grey--text {{$t('common:header.currentPage')}} .overline.pa-4.grey--text {{$t('common:header.currentPage')}}
v-list-item.pl-4(@click='pageView', v-if='mode !== `view`') v-list-item.pl-4(@click='pageView', v-if='mode !== `view`')
v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-file-document-box-outline v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-file-document-outline
v-list-item-title.body-2 {{$t('common:header.view')}} v-list-item-title.body-2 {{$t('common:header.view')}}
v-list-item.pl-4(@click='pageEdit', v-if='mode !== `edit` && isAuthenticated') v-list-item.pl-4(@click='pageEdit', v-if='mode !== `edit` && hasWritePagesPermission')
v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-file-document-edit-outline v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-file-document-edit-outline
v-list-item-title.body-2 {{$t('common:header.edit')}} v-list-item-title.body-2 {{$t('common:header.edit')}}
v-list-item.pl-4(@click='pageHistory', v-if='mode !== `history`') v-list-item.pl-4(@click='pageHistory', v-if='mode !== `history` && hasReadHistoryPermission')
v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-history v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-history
v-list-item-content v-list-item-content
v-list-item-title.body-2 {{$t('common:header.history')}} v-list-item-title.body-2 {{$t('common:header.history')}}
v-list-item.pl-4(@click='pageSource', v-if='mode !== `source`') 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='pageDuplicate', v-if='isAuthenticated') 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')}}
v-list-item.pl-4(@click='pageMove', v-if='isAuthenticated') v-list-item.pl-4(@click='pageMove', v-if='hasManagePagesPermission')
v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-content-save-move-outline v-list-item-avatar(size='24', tile): v-icon(color='indigo') mdi-content-save-move-outline
v-list-item-content v-list-item-content
v-list-item-title.body-2 {{$t('common:header.move')}} v-list-item-title.body-2 {{$t('common:header.move')}}
v-list-item.pl-4(@click='pageDelete', v-if='isAuthenticated') v-list-item.pl-4(@click='pageDelete', v-if='hasDeletePagesPermission')
v-list-item-avatar(size='24', tile): v-icon(color='red darken-2') mdi-trash-can-outline v-list-item-avatar(size='24', tile): v-icon(color='red darken-2') mdi-trash-can-outline
v-list-item-title.body-2 {{$t('common:header.delete')}} v-list-item-title.body-2 {{$t('common:header.delete')}}
v-divider(vertical) v-divider(vertical)
//- NEW PAGE //- NEW PAGE
template(v-if='isAuthenticated && path && mode !== `edit`') template(v-if='hasNewPagePermission && path && mode !== `edit`')
v-tooltip(bottom) v-tooltip(bottom)
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-btn(icon, tile, height='64', v-on='on', @click='pageNew') v-btn(icon, tile, height='64', v-on='on', @click='pageNew')
@ -288,6 +288,19 @@ export default {
}, },
isAdmin () { isAdmin () {
return _.intersection(this.permissions, ['manage:system', 'write:users', 'manage:users', 'write:groups', 'manage:groups', 'manage:navigation', 'manage:theme', 'manage:api']).length > 0 return _.intersection(this.permissions, ['manage:system', 'write:users', 'manage:users', 'write:groups', 'manage:groups', 'manage:navigation', 'manage:theme', 'manage:api']).length > 0
},
hasNewPagePermission () {
return this.hasAdminPermission || _.intersection(this.permissions, ['write:pages']).length > 0
},
hasAdminPermission: get('page/effectivePermissions@system.manage'),
hasWritePagesPermission: get('page/effectivePermissions@pages.write'),
hasManagePagesPermission: get('page/effectivePermissions@pages.manage'),
hasDeletePagesPermission: get('page/effectivePermissions@pages.delete'),
hasReadSourcePermission: get('page/effectivePermissions@source.read'),
hasReadHistoryPermission: get('page/effectivePermissions@history.read'),
hasAnyPagePermissions () {
return this.hasAdminPermission || this.hasWritePagesPermission || this.hasManagePagesPermission ||
this.hasDeletePagesPermission || this.hasReadSourcePermission || this.hasReadHistoryPermission
} }
}, },
created () { created () {

View File

@ -133,6 +133,10 @@ export default {
checkoutDate: { checkoutDate: {
type: String, type: String,
default: new Date().toISOString() default: new Date().toISOString()
},
effectivePermissions: {
type: String,
default: ''
} }
}, },
data() { data() {
@ -197,6 +201,10 @@ export default {
this.setCurrentSavedState() this.setCurrentSavedState()
this.checkoutDateActive = this.checkoutDate this.checkoutDateActive = this.checkoutDate
if (this.effectivePermissions) {
this.$store.set('page/effectivePermissions',JSON.parse(Buffer.from(this.effectivePermissions, 'base64').toString()))
}
}, },
mounted() { mounted() {
this.$store.set('editor/mode', this.initMode || 'create') this.$store.set('editor/mode', this.initMode || 'create')

View File

@ -185,6 +185,10 @@ export default {
liveContent: { liveContent: {
type: String, type: String,
default: '' default: ''
},
effectivePermissions: {
type: String,
default: ''
} }
}, },
data () { data () {
@ -316,6 +320,10 @@ export default {
}) })
this.target = this.cache[0] this.target = this.cache[0]
if (this.effectivePermissions) {
this.$store.set('page/effectivePermissions',JSON.parse(Buffer.from(this.effectivePermissions, 'base64').toString()))
}
}, },
methods: { methods: {
async loadVersion (versionId) { async loadVersion (versionId) {

View File

@ -50,6 +50,10 @@ export default {
versionDate: { versionDate: {
type: String, type: String,
default: '' default: ''
},
effectivePermissions: {
type: String,
default: ''
} }
}, },
data() { data() {
@ -60,7 +64,11 @@ export default {
this.$store.commit('page/SET_LOCALE', this.locale) this.$store.commit('page/SET_LOCALE', this.locale)
this.$store.commit('page/SET_PATH', this.path) this.$store.commit('page/SET_PATH', this.path)
this.$store.commit('page/SET_MODE', 'history') this.$store.commit('page/SET_MODE', 'source')
if (this.effectivePermissions) {
this.$store.set('page/effectivePermissions',JSON.parse(Buffer.from(this.effectivePermissions, 'base64').toString()))
}
}, },
methods: { methods: {
goLive() { goLive() {

View File

@ -15,11 +15,27 @@ const state = {
title: '', title: '',
updatedAt: '', updatedAt: '',
mode: '', mode: '',
commentsPermissions: { effectivePermissions: {
comments: {
read: false, read: false,
write: false, write: false,
manage: false manage: false
}, },
history: {
read: false
},
source: {
read: false
},
pages: {
write: false,
manage: false,
delete: false
},
system: {
manage: false
}
},
commentsCount: 0 commentsCount: 0
} }

View File

@ -132,7 +132,7 @@
v-spacer v-spacer
v-tooltip(right, v-if='isAuthenticated') v-tooltip(right, v-if='isAuthenticated')
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-btn.btn-animate-edit(icon, :href='"/h/" + locale + "/" + path', v-on='on', x-small) v-btn.btn-animate-edit(icon, :href='"/h/" + locale + "/" + path', v-on='on', x-small, v-if="hasReadHistoryPermission")
v-icon(color='indigo', dense) mdi-history v-icon(color='indigo', dense) mdi-history
span {{$t('common:header.history')}} span {{$t('common:header.history')}}
.body-2.grey--text(:class='$vuetify.theme.dark ? `` : `text--darken-3`') {{ authorName }} .body-2.grey--text(:class='$vuetify.theme.dark ? `` : `text--darken-3`') {{ authorName }}
@ -176,7 +176,7 @@
v-spacer v-spacer
v-flex.page-col-content(xs12, lg9, xl10) v-flex.page-col-content(xs12, lg9, xl10)
v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='isAuthenticated') v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasAnyPagePermissions')
template(v-slot:activator='{ on: onEditActivator }') template(v-slot:activator='{ on: onEditActivator }')
v-speed-dial( v-speed-dial(
v-model='pageEditFab' v-model='pageEditFab'
@ -196,9 +196,10 @@
v-model='pageEditFab' v-model='pageEditFab'
@click='pageEdit' @click='pageEdit'
v-on='onEditActivator' v-on='onEditActivator'
:disabled='!hasWritePagesPermission'
) )
v-icon mdi-pencil v-icon mdi-pencil
v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl') v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasReadHistoryPermission')
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-btn( v-btn(
fab fab
@ -210,7 +211,7 @@
) )
v-icon(size='20') mdi-history v-icon(size='20') mdi-history
span {{$t('common:header.history')}} span {{$t('common:header.history')}}
v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl') v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasReadSourcePermission')
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-btn( v-btn(
fab fab
@ -222,7 +223,7 @@
) )
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-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasWritePagesPermission')
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-btn( v-btn(
fab fab
@ -234,7 +235,7 @@
) )
v-icon(size='20') mdi-content-duplicate v-icon(size='20') mdi-content-duplicate
span {{$t('common:header.duplicate')}} span {{$t('common:header.duplicate')}}
v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl') v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasManagePagesPermission')
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-btn( v-btn(
fab fab
@ -246,7 +247,7 @@
) )
v-icon(size='20') mdi-content-save-move-outline v-icon(size='20') mdi-content-save-move-outline
span {{$t('common:header.move')}} span {{$t('common:header.move')}}
v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl') v-tooltip(:right='$vuetify.rtl', :left='!$vuetify.rtl', v-if='hasDeletePagesPermission')
template(v-slot:activator='{ on }') template(v-slot:activator='{ on }')
v-btn( v-btn(
fab fab
@ -402,7 +403,7 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
commentsPermissions: { effectivePermissions: {
type: String, type: String,
default: '' default: ''
}, },
@ -446,7 +447,7 @@ export default {
computed: { computed: {
isAuthenticated: get('user/authenticated'), isAuthenticated: get('user/authenticated'),
commentsCount: get('page/commentsCount'), commentsCount: get('page/commentsCount'),
commentsPerms: get('page/commentsPermissions'), commentsPerms: get('page/effectivePermissions@comments'),
rating: { rating: {
get () { get () {
return 3.5 return 3.5
@ -477,6 +478,16 @@ export default {
}, },
tocDecoded () { tocDecoded () {
return JSON.parse(Buffer.from(this.toc, 'base64').toString()) return JSON.parse(Buffer.from(this.toc, 'base64').toString())
},
hasAdminPermission: get('page/effectivePermissions@system.manage'),
hasWritePagesPermission: get('page/effectivePermissions@pages.write'),
hasManagePagesPermission: get('page/effectivePermissions@pages.manage'),
hasDeletePagesPermission: get('page/effectivePermissions@pages.delete'),
hasReadSourcePermission: get('page/effectivePermissions@source.read'),
hasReadHistoryPermission: get('page/effectivePermissions@history.read'),
hasAnyPagePermissions () {
return this.hasAdminPermission || this.hasWritePagesPermission || this.hasManagePagesPermission ||
this.hasDeletePagesPermission || this.hasReadSourcePermission || this.hasReadHistoryPermission
} }
}, },
created() { created() {
@ -491,8 +502,8 @@ export default {
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/updatedAt', this.updatedAt) this.$store.set('page/updatedAt', this.updatedAt)
if (this.commentsPermissions) { if (this.effectivePermissions) {
this.$store.set('page/commentsPermissions', JSON.parse(atob(this.commentsPermissions))) this.$store.set('page/effectivePermissions',JSON.parse(Buffer.from(this.effectivePermissions, 'base64').toString()))
} }
this.$store.set('page/mode', 'view') this.$store.set('page/mode', 'view')

View File

@ -7,6 +7,30 @@ const _ = require('lodash')
const tmplCreateRegex = /^[0-9]+(,[0-9]+)?$/ const tmplCreateRegex = /^[0-9]+(,[0-9]+)?$/
const getPageEffectivePermissions = (req, page) => {
return {
comments: {
read: WIKI.config.features.featurePageComments ? WIKI.auth.checkAccess(req.user, ['read:comments'], page) : false,
write: WIKI.config.features.featurePageComments ? WIKI.auth.checkAccess(req.user, ['write:comments'], page) : false,
manage: WIKI.config.features.featurePageComments ? WIKI.auth.checkAccess(req.user, ['manage:comments'], page) : false
},
history: {
read: WIKI.auth.checkAccess(req.user, ['read:history'], page)
},
source: {
read: WIKI.auth.checkAccess(req.user, ['read:source'], page)
},
pages: {
write: WIKI.auth.checkAccess(req.user, ['write:pages'], page),
manage: WIKI.auth.checkAccess(req.user, ['manage:pages'], page),
delete: WIKI.auth.checkAccess(req.user, ['delete:pages'], page)
},
system: {
manage: WIKI.auth.checkAccess(req.user, ['manage:system'], page)
}
}
}
/** /**
* Robots.txt * Robots.txt
*/ */
@ -196,7 +220,11 @@ router.get(['/e', '/e/*'], async (req, res, next) => {
} }
} }
} }
res.render('editor', { page, injectCode })
// -> Effective Permissions
const effectivePermissions = getPageEffectivePermissions(req, pageArgs)
res.render('editor', { page, injectCode, effectivePermissions })
}) })
/** /**
@ -234,7 +262,11 @@ router.get(['/h', '/h/*'], async (req, res, next) => {
if (page) { if (page) {
_.set(res.locals, 'pageMeta.title', page.title) _.set(res.locals, 'pageMeta.title', page.title)
_.set(res.locals, 'pageMeta.description', page.description) _.set(res.locals, 'pageMeta.description', page.description)
res.render('history', { page })
// -> Effective Permissions
const effectivePermissions = getPageEffectivePermissions(req, pageArgs)
res.render('history', { page, effectivePermissions })
} else { } else {
res.redirect(`/${pageArgs.path}`) res.redirect(`/${pageArgs.path}`)
} }
@ -335,7 +367,11 @@ router.get(['/s', '/s/*'], async (req, res, next) => {
} else { } else {
_.set(res.locals, 'pageMeta.title', page.title) _.set(res.locals, 'pageMeta.title', page.title)
_.set(res.locals, 'pageMeta.description', page.description) _.set(res.locals, 'pageMeta.description', page.description)
res.render('source', { page })
// -> Effective Permissions
const effectivePermissions = getPageEffectivePermissions(req, pageArgs)
res.render('source', { page, effectivePermissions })
} }
} else { } else {
res.redirect(`/${pageArgs.path}`) res.redirect(`/${pageArgs.path}`)
@ -447,16 +483,8 @@ router.get('/*', async (req, res, next) => {
}) })
} }
// -> Comments Permissions // -> Effective Permissions
const commentsPermissions = WIKI.config.features.featurePageComments ? { const effectivePermissions = getPageEffectivePermissions(req, pageArgs)
read: WIKI.auth.checkAccess(req.user, ['read:comments'], pageArgs),
write: WIKI.auth.checkAccess(req.user, ['write:comments'], pageArgs),
manage: WIKI.auth.checkAccess(req.user, ['manage:comments'], pageArgs)
} : {
read: false,
write: false,
manage: false
}
// -> Render view // -> Render view
res.render('page', { res.render('page', {
@ -464,7 +492,7 @@ router.get('/*', async (req, res, next) => {
sidebar, sidebar,
injectCode, injectCode,
comments: WIKI.data.commentProvider, comments: WIKI.data.commentProvider,
commentsPermissions effectivePermissions
}) })
} }
} else if (pageArgs.path === 'home') { } else if (pageArgs.path === 'home') {

View File

@ -18,4 +18,5 @@ block body
init-editor=page.editorKey init-editor=page.editorKey
init-content=page.content init-content=page.content
checkout-date=page.updatedAt checkout-date=page.updatedAt
effective-permissions=Buffer.from(JSON.stringify(effectivePermissions)).toString('base64')
) )

View File

@ -17,4 +17,5 @@ block body
:author-id=page.authorId :author-id=page.authorId
:is-published=page.isPublished.toString() :is-published=page.isPublished.toString()
live-content=page.content live-content=page.content
effective-permissions=Buffer.from(JSON.stringify(effectivePermissions)).toString('base64')
) )

View File

@ -26,7 +26,7 @@ block body
sidebar=Buffer.from(JSON.stringify(sidebar)).toString('base64') sidebar=Buffer.from(JSON.stringify(sidebar)).toString('base64')
nav-mode=config.nav.mode nav-mode=config.nav.mode
comments-enabled=config.features.featurePageComments comments-enabled=config.features.featurePageComments
comments-permissions=Buffer.from(JSON.stringify(commentsPermissions)).toString('base64') effective-permissions=Buffer.from(JSON.stringify(effectivePermissions)).toString('base64')
comments-external=comments.codeTemplate comments-external=comments.codeTemplate
) )
template(slot='contents') template(slot='contents')

View File

@ -10,4 +10,5 @@ block body
path=page.path path=page.path
:version-id=page.versionId :version-id=page.versionId
version-date=page.versionDate version-date=page.versionDate
effective-permissions=Buffer.from(JSON.stringify(effectivePermissions)).toString('base64')
)= page.content )= page.content