feat: add Page Rules For Matching Tags (#1418)

* Added Page Rules For Matching Tags

* fix: use T as Tag Match icon

* fix: reorder page rules in checkAccess

* fix: common controller tags code refactor

Co-authored-by: Nicolas Giard <github@ngpixel.com>
This commit is contained in:
BobbyB 2020-01-31 16:57:35 -05:00 committed by GitHub
parent 4e9d4071fd
commit b82c788e5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 26 deletions

View File

@ -157,8 +157,8 @@
solo solo
v-model='rule.path' v-model='rule.path'
label='Path' label='Path'
:prefix='rule.match !== `END` ? `/` : null' :prefix='(rule.match !== `END` && rule.match !== `TAG`) ? `/` : null'
:placeholder='rule.match === `REGEX` ? `Regular Expression` : `Path`' :placeholder='rule.match === `REGEX` ? `Regular Expression` : rule.match === `TAG` ? `Tag` : `Path`'
:suffix='rule.match === `REGEX` ? `/` : null' :suffix='rule.match === `REGEX` ? `/` : null'
hide-details hide-details
:color='$vuetify.theme.dark ? `grey` : `blue-grey`' :color='$vuetify.theme.dark ? `grey` : `blue-grey`'
@ -181,6 +181,8 @@
strong Path Ends With... strong Path Ends With...
li li
strong Path Matches Regex... strong Path Matches Regex...
li
strong Tag Matches...
li li
strong Path Is Exactly... strong Path Is Exactly...
em.caption.pl-1 (highest) em.caption.pl-1 (highest)
@ -222,7 +224,8 @@ export default {
{ text: 'Path Starts With...', value: 'START', icon: '/...' }, { text: 'Path Starts With...', value: 'START', icon: '/...' },
{ text: 'Path is Exactly...', value: 'EXACT', icon: '=' }, { text: 'Path is Exactly...', value: 'EXACT', icon: '=' },
{ text: 'Path Ends With...', value: 'END', icon: '.../' }, { text: 'Path Ends With...', value: 'END', icon: '.../' },
{ text: 'Path Matches Regex...', value: 'REGEX', icon: '$.*' } { text: 'Path Matches Regex...', value: 'REGEX', icon: '$.*' },
{ text: 'Tag Matches...', value: 'TAG', icon: 'T' }
], ],
locales: [ locales: [
{ text: 'English', value: 'en' } { text: 'English', value: 'en' }

View File

@ -59,6 +59,8 @@ router.get(['/e', '/e/*'], async (req, res, next) => {
isPrivate: false isPrivate: false
}) })
pageArgs.tags = _.get(page, 'tags', [])
const injectCode = { const injectCode = {
css: WIKI.config.theming.injectCSS, css: WIKI.config.theming.injectCSS,
head: WIKI.config.theming.injectHead, head: WIKI.config.theming.injectHead,
@ -109,17 +111,20 @@ router.get(['/h', '/h/*'], async (req, res, next) => {
_.set(res, 'locals.siteConfig.lang', pageArgs.locale) _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
if (!WIKI.auth.checkAccess(req.user, ['read:history'], pageArgs)) {
_.set(res.locals, 'pageMeta.title', 'Unauthorized')
return res.render('unauthorized', { action: 'history' })
}
const page = await WIKI.models.pages.getPageFromDb({ const page = await WIKI.models.pages.getPageFromDb({
path: pageArgs.path, path: pageArgs.path,
locale: pageArgs.locale, locale: pageArgs.locale,
userId: req.user.id, userId: req.user.id,
isPrivate: false isPrivate: false
}) })
pageArgs.tags = _.get(page, 'tags', [])
if (!WIKI.auth.checkAccess(req.user, ['read:history'], pageArgs)) {
_.set(res.locals, 'pageMeta.title', 'Unauthorized')
return res.render('unauthorized', { action: 'history' })
}
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)
@ -149,7 +154,8 @@ router.get(['/i', '/i/:id'], async (req, res, next) => {
path: page.path, path: page.path,
private: page.isPrivate, private: page.isPrivate,
privateNS: page.privateNS, privateNS: page.privateNS,
explicitLocale: false explicitLocale: false,
tags: page.tags
})) { })) {
_.set(res.locals, 'pageMeta.title', 'Unauthorized') _.set(res.locals, 'pageMeta.title', 'Unauthorized')
return res.render('unauthorized', { action: 'view' }) return res.render('unauthorized', { action: 'view' })
@ -175,6 +181,14 @@ router.get(['/p', '/p/*'], (req, res, next) => {
*/ */
router.get(['/s', '/s/*'], async (req, res, next) => { router.get(['/s', '/s/*'], async (req, res, next) => {
const pageArgs = pageHelper.parsePath(req.path, { stripExt: true }) const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
const page = await WIKI.models.pages.getPageFromDb({
path: pageArgs.path,
locale: pageArgs.locale,
userId: req.user.id,
isPrivate: false
})
pageArgs.tags = _.get(page, 'tags', [])
if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) { if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
return res.redirect(`/s/${pageArgs.locale}/${pageArgs.path}`) return res.redirect(`/s/${pageArgs.locale}/${pageArgs.path}`)
@ -186,12 +200,6 @@ router.get(['/s', '/s/*'], async (req, res, next) => {
return res.render('unauthorized', { action: 'source' }) return res.render('unauthorized', { action: 'source' })
} }
const page = await WIKI.models.pages.getPageFromDb({
path: pageArgs.path,
locale: pageArgs.locale,
userId: req.user.id,
isPrivate: false
})
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)
@ -224,14 +232,6 @@ router.get('/*', async (req, res, next) => {
req.i18n.changeLanguage(pageArgs.locale) req.i18n.changeLanguage(pageArgs.locale)
if (!WIKI.auth.checkAccess(req.user, ['read:pages'], pageArgs)) {
if (pageArgs.path === 'home') {
return res.redirect('/login')
}
_.set(res.locals, 'pageMeta.title', 'Unauthorized')
return res.status(403).render('unauthorized', { action: 'view' })
}
try { try {
const page = await WIKI.models.pages.getPage({ const page = await WIKI.models.pages.getPage({
path: pageArgs.path, path: pageArgs.path,
@ -239,6 +239,17 @@ router.get('/*', async (req, res, next) => {
userId: req.user.id, userId: req.user.id,
isPrivate: false isPrivate: false
}) })
pageArgs.tags = _.get(page, 'tags', [])
if (!WIKI.auth.checkAccess(req.user, ['read:pages'], pageArgs)) {
if (pageArgs.path === 'home') {
return res.redirect('/login')
}
_.set(res.locals, 'pageMeta.title', 'Unauthorized')
return res.status(403).render('unauthorized', {
action: 'view'
})
}
_.set(res, 'locals.siteConfig.lang', pageArgs.locale) _.set(res, 'locals.siteConfig.lang', pageArgs.locale)

View File

@ -176,20 +176,31 @@ module.exports = {
switch (rule.match) { switch (rule.match) {
case 'START': case 'START':
if (_.startsWith(`/${page.path}`, `/${rule.path}`)) { if (_.startsWith(`/${page.path}`, `/${rule.path}`)) {
checkState = this._applyPageRuleSpecificity({ rule, checkState, higherPriority: ['END', 'REGEX', 'EXACT'] }) checkState = this._applyPageRuleSpecificity({ rule, checkState, higherPriority: ['END', 'REGEX', 'EXACT', 'TAG'] })
} }
break break
case 'END': case 'END':
if (_.endsWith(page.path, rule.path)) { if (_.endsWith(page.path, rule.path)) {
checkState = this._applyPageRuleSpecificity({ rule, checkState, higherPriority: ['REGEX', 'EXACT'] }) checkState = this._applyPageRuleSpecificity({ rule, checkState, higherPriority: ['REGEX', 'EXACT', 'TAG'] })
} }
break break
case 'REGEX': case 'REGEX':
const reg = new RegExp(rule.path) const reg = new RegExp(rule.path)
if (reg.test(page.path)) { if (reg.test(page.path)) {
checkState = this._applyPageRuleSpecificity({ rule, checkState, higherPriority: ['EXACT'] }) checkState = this._applyPageRuleSpecificity({ rule, checkState, higherPriority: ['EXACT', 'TAG'] })
} }
break break
case 'TAG':
_.get(page, 'tags', []).forEach(tag => {
if (tag.tag === rule.path) {
checkState = this._applyPageRuleSpecificity({
rule,
checkState,
higherPriority: ['EXACT']
})
}
})
break
case 'EXACT': case 'EXACT':
if (`/${page.path}` === `/${rule.path}`) { if (`/${page.path}` === `/${rule.path}`) {
checkState = this._applyPageRuleSpecificity({ rule, checkState, higherPriority: [] }) checkState = this._applyPageRuleSpecificity({ rule, checkState, higherPriority: [] })

View File

@ -108,4 +108,5 @@ enum PageRuleMatch {
EXACT EXACT
END END
REGEX REGEX
TAG
} }