From 4cc516b85404b6d244f3be5385f35ffab64ed946 Mon Sep 17 00:00:00 2001 From: corsacca Date: Mon, 27 Apr 2026 09:54:44 +0100 Subject: [PATCH] Make CMS pages permissions more granular. --- app/pages/admin/index.vue | 2 +- app/utils/permissions.ts | 13 +++++++++---- server/api/admin/cache/flush.post.ts | 2 +- server/api/admin/categories/[id].delete.ts | 2 +- server/api/admin/categories/[id].patch.ts | 2 +- .../api/admin/categories/[id]/page-order.patch.ts | 2 +- server/api/admin/categories/index.post.ts | 2 +- server/api/admin/pages/[id].delete.ts | 2 +- server/api/admin/pages/[id].patch.ts | 2 +- server/api/admin/pages/[id]/publish.post.ts | 2 +- server/api/admin/pages/[id]/translate.post.ts | 2 +- .../admin/pages/[id]/translations/[locale].put.ts | 2 +- server/api/admin/pages/index.post.ts | 2 +- server/api/admin/upload/image.post.ts | 2 +- 14 files changed, 22 insertions(+), 17 deletions(-) diff --git a/app/pages/admin/index.vue b/app/pages/admin/index.vue index c637d2a5..f11bcccb 100644 --- a/app/pages/admin/index.vue +++ b/app/pages/admin/index.vue @@ -35,7 +35,7 @@ async function flushCache() {

Dashboard

-
+

CMS cache

Every edit auto-purges the pages it touches. Use this when you've diff --git a/app/utils/permissions.ts b/app/utils/permissions.ts index c4a8cb64..909f5e1f 100644 --- a/app/utils/permissions.ts +++ b/app/utils/permissions.ts @@ -10,7 +10,8 @@ export const PERMISSIONS = [ 'roles.view', 'roles.manage', 'pages.view', - 'pages.manage' + 'pages.write', + 'pages.publish' ] as const export type Permission = typeof PERMISSIONS[number] @@ -43,9 +44,13 @@ export const PERMISSION_META: Record { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const user = await getAuthUser(event) const count = await purgeAllCmsCache() logEvent({ diff --git a/server/api/admin/categories/[id].delete.ts b/server/api/admin/categories/[id].delete.ts index 861823a5..003fb537 100644 --- a/server/api/admin/categories/[id].delete.ts +++ b/server/api/admin/categories/[id].delete.ts @@ -8,7 +8,7 @@ import { deleteCategory } from '../../../database/categories' import { logDelete } from '../../../utils/activity-logger' export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const id = getRouterParam(event, 'id') if (!id) throw createError({ statusCode: 400, statusMessage: 'id is required' }) diff --git a/server/api/admin/categories/[id].patch.ts b/server/api/admin/categories/[id].patch.ts index 39028502..b7167ae3 100644 --- a/server/api/admin/categories/[id].patch.ts +++ b/server/api/admin/categories/[id].patch.ts @@ -32,7 +32,7 @@ function normalizeTranslations( } export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const id = getRouterParam(event, 'id') if (!id) throw createError({ statusCode: 400, statusMessage: 'id is required' }) diff --git a/server/api/admin/categories/[id]/page-order.patch.ts b/server/api/admin/categories/[id]/page-order.patch.ts index 1e0cb09f..f9853f22 100644 --- a/server/api/admin/categories/[id]/page-order.patch.ts +++ b/server/api/admin/categories/[id]/page-order.patch.ts @@ -10,7 +10,7 @@ import { reorderCategoryPages, getCategoryPages, purgeSlugs } from '../../../../ import { logUpdate } from '../../../../utils/activity-logger' export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const id = getRouterParam(event, 'id') if (!id) throw createError({ statusCode: 400, statusMessage: 'id is required' }) diff --git a/server/api/admin/categories/index.post.ts b/server/api/admin/categories/index.post.ts index 67082feb..f0ee8069 100644 --- a/server/api/admin/categories/index.post.ts +++ b/server/api/admin/categories/index.post.ts @@ -37,7 +37,7 @@ function normalizeTranslations( } export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const body = await readBody(event) const slug = (body?.slug ?? '').trim().replace(/^\/+|\/+$/g, '') diff --git a/server/api/admin/pages/[id].delete.ts b/server/api/admin/pages/[id].delete.ts index 8e5ef7fd..a1fef80c 100644 --- a/server/api/admin/pages/[id].delete.ts +++ b/server/api/admin/pages/[id].delete.ts @@ -8,7 +8,7 @@ import { logDelete } from '../../../utils/activity-logger' import { purgeCmsPage, purgeCmsCategory } from '../../../utils/cmsCache' export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const id = getRouterParam(event, 'id') if (!id) throw createError({ statusCode: 400, statusMessage: 'id is required' }) diff --git a/server/api/admin/pages/[id].patch.ts b/server/api/admin/pages/[id].patch.ts index b55e4872..cdf78fe5 100644 --- a/server/api/admin/pages/[id].patch.ts +++ b/server/api/admin/pages/[id].patch.ts @@ -11,7 +11,7 @@ import { logUpdate } from '../../../utils/activity-logger' import { purgeCmsPage } from '../../../utils/cmsCache' export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const id = getRouterParam(event, 'id') if (!id) throw createError({ statusCode: 400, statusMessage: 'id is required' }) diff --git a/server/api/admin/pages/[id]/publish.post.ts b/server/api/admin/pages/[id]/publish.post.ts index 23303d20..49269fe3 100644 --- a/server/api/admin/pages/[id]/publish.post.ts +++ b/server/api/admin/pages/[id]/publish.post.ts @@ -13,7 +13,7 @@ interface Body { } export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.publish') const id = getRouterParam(event, 'id') if (!id) throw createError({ statusCode: 400, statusMessage: 'id is required' }) diff --git a/server/api/admin/pages/[id]/translate.post.ts b/server/api/admin/pages/[id]/translate.post.ts index 32ccb1f3..ff51fdb4 100644 --- a/server/api/admin/pages/[id]/translate.post.ts +++ b/server/api/admin/pages/[id]/translate.post.ts @@ -20,7 +20,7 @@ interface Body { } export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') if (!isDeepLConfigured()) { throw createError({ statusCode: 500, statusMessage: 'DEEPL_API_KEY is not configured' }) } diff --git a/server/api/admin/pages/[id]/translations/[locale].put.ts b/server/api/admin/pages/[id]/translations/[locale].put.ts index 20d0f120..c9574630 100644 --- a/server/api/admin/pages/[id]/translations/[locale].put.ts +++ b/server/api/admin/pages/[id]/translations/[locale].put.ts @@ -22,7 +22,7 @@ interface Body { } export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const id = getRouterParam(event, 'id') const locale = getRouterParam(event, 'locale') if (!id) throw createError({ statusCode: 400, statusMessage: 'id is required' }) diff --git a/server/api/admin/pages/index.post.ts b/server/api/admin/pages/index.post.ts index 7479d5d7..9d295355 100644 --- a/server/api/admin/pages/index.post.ts +++ b/server/api/admin/pages/index.post.ts @@ -9,7 +9,7 @@ import { logCreate } from '../../../utils/activity-logger' import { purgeCmsCategory } from '../../../utils/cmsCache' export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const body = await readBody<{ slug?: string; category_id?: string | null; menu_order?: number }>(event) const slug = (body?.slug ?? '').trim().replace(/^\/+|\/+$/g, '') diff --git a/server/api/admin/upload/image.post.ts b/server/api/admin/upload/image.post.ts index 2f7f4297..f5e04c25 100644 --- a/server/api/admin/upload/image.post.ts +++ b/server/api/admin/upload/image.post.ts @@ -11,7 +11,7 @@ import { uploadToS3, validateImageType, validateFileSize } from '../../../utils/ const MAX_IMAGE_MB = 10 export default defineEventHandler(async (event) => { - await requirePermission(event, 'pages.manage') + await requirePermission(event, 'pages.write') const form = await readMultipartFormData(event) const file = form?.find(p => p.name === 'file')