1
0
Fork 0
mirror of synced 2024-07-30 02:26:11 +12:00

Ensure view names are properly encoded to handle certain special characters (#9145)

This commit is contained in:
Andrew Kingston 2022-12-22 13:09:07 +00:00 committed by GitHub
parent 3a204b72e8
commit 66674c7277
9 changed files with 32 additions and 16 deletions

View file

@ -10,6 +10,7 @@
$: views = $tables.list.flatMap(table => Object.keys(table.views || {}))
const saveView = async () => {
name = name?.trim()
if (views.includes(name)) {
notifications.error(`View exists with name ${name}`)
return
@ -21,7 +22,7 @@
field,
})
notifications.success(`View ${name} created`)
$goto(`../../view/${name}`)
$goto(`../../view/${encodeURIComponent(name)}`)
} catch (error) {
notifications.error("Error creating view")
}

View file

@ -36,9 +36,8 @@
indentLevel={2}
icon="Remove"
text={viewName}
selected={$isActive("./view/:viewName") &&
$views.selected?.name === viewName}
on:click={() => $goto(`./view/${viewName}`)}
selected={$isActive("./view") && $views.selected?.name === viewName}
on:click={() => $goto(`./view/${encodeURIComponent(viewName)}`)}
>
<EditViewPopover
view={{ name: viewName, ...table.views[viewName] }}

View file

@ -33,7 +33,8 @@
async function deleteView() {
try {
const isSelected = $params.viewName === $views.selectedViewName
const isSelected =
decodeURIComponent($params.viewName) === $views.selectedViewName
const name = view.name
const id = view.tableId
await views.delete(name)

View file

@ -12,6 +12,7 @@ export const syncURLToState = options => {
store,
routify,
beforeNavigate,
decode,
} = options || {}
if (
!urlParam ||
@ -29,11 +30,23 @@ export const syncURLToState = options => {
return
}
// Decodes encoded URL params if required
const decodeParams = urlParams => {
if (!decode) {
return urlParams
}
let decoded = {}
Object.keys(urlParams || {}).forEach(key => {
decoded[key] = decode(urlParams[key])
})
return decoded
}
// We can't dynamically fetch the value of stateful routify stores so we need
// to just subscribe and cache the latest versions.
// We can grab their initial values as this is during component
// initialisation.
let cachedParams = get(routify.params)
let cachedParams = decodeParams(get(routify.params))
let cachedGoto = get(routify.goto)
let cachedRedirect = get(routify.redirect)
let cachedPage = get(routify.page)
@ -77,7 +90,7 @@ export const syncURLToState = options => {
// Check if new value is valid
if (validate && fallbackUrl) {
if (!validate(urlValue)) {
log("Invalid URL param!")
log("Invalid URL param!", urlValue)
redirectUrl(fallbackUrl)
return
}
@ -109,7 +122,7 @@ export const syncURLToState = options => {
log(`url.${urlParam} (${urlValue}) <= state.${stateKey} (${stateValue})`)
if (validate && fallbackUrl) {
if (!validate(stateValue)) {
log("Invalid state param!")
log("Invalid state param!", stateValue)
redirectUrl(fallbackUrl)
return
}
@ -137,6 +150,7 @@ export const syncURLToState = options => {
// Subscribe to URL changes and cache them
const unsubscribeParams = routify.params.subscribe($urlParams => {
$urlParams = decodeParams($urlParams)
cachedParams = $urlParams
mapUrlToState($urlParams)
})

View file

@ -12,6 +12,7 @@
fallbackUrl: "../",
store: views,
routify,
decode: decodeURIComponent,
})
onDestroy(stopSyncing)

View file

@ -6,9 +6,9 @@
onMount(async () => {
const { list, selected } = $views
if (selected) {
$redirect(`./${selected?.name}`)
$redirect(`./${encodeURIComponent(selected?.name)}`)
} else if (list?.length) {
$redirect(`./${list[0].name}`)
$redirect(`./${encodeURIComponent(list[0].name)}`)
} else {
$redirect("../")
}

View file

@ -16,8 +16,8 @@ export const buildViewEndpoints = API => ({
params.set("group", groupBy)
}
const QUERY_VIEW_URL = field
? `/api/views/${name}?${params}`
: `/api/views/${name}`
? `/api/views/${encodeURIComponent(name)}?${params}`
: `/api/views/${encodeURIComponent(name)}`
return await API.get({ url: QUERY_VIEW_URL })
},
@ -53,7 +53,7 @@ export const buildViewEndpoints = API => ({
*/
deleteView: async viewName => {
return await API.delete({
url: `/api/views/${viewName}`,
url: `/api/views/${encodeURIComponent(viewName)}`,
})
},
})

View file

@ -187,7 +187,7 @@ export async function save(ctx: UserCtx) {
}
export async function fetchView(ctx: Ctx) {
const viewName = ctx.params.viewName
const viewName = decodeURIComponent(ctx.params.viewName)
// if this is a table view being looked for just transfer to that
if (viewName.startsWith(DocumentType.TABLE)) {

View file

@ -113,7 +113,7 @@ async function handleViewEvents(existingView: View, newView: View) {
export async function destroy(ctx: BBContext) {
const db = context.getAppDB()
const viewName = decodeURI(ctx.params.viewName)
const viewName = decodeURIComponent(ctx.params.viewName)
const view = await deleteView(viewName)
const table = await db.get(view.meta.tableId)
delete table.views[viewName]
@ -124,7 +124,7 @@ export async function destroy(ctx: BBContext) {
}
export async function exportView(ctx: BBContext) {
const viewName = decodeURI(ctx.query.view as string)
const viewName = decodeURIComponent(ctx.query.view as string)
const view = await getView(viewName)
const format = ctx.query.format as string