From 648101860c49891aba8a537acb9c4eb76e529fb6 Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Tue, 10 Feb 2026 16:31:51 -0800 Subject: [PATCH] short circuit sidebar permissions --- apps/server/src/core/page/page.controller.ts | 6 ++ .../src/core/page/services/page.service.ts | 76 +++++++++++-------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/apps/server/src/core/page/page.controller.ts b/apps/server/src/core/page/page.controller.ts index c27573b9..479f0579 100644 --- a/apps/server/src/core/page/page.controller.ts +++ b/apps/server/src/core/page/page.controller.ts @@ -298,11 +298,17 @@ export class PageController { throw new ForbiddenException(); } + const spaceCanEdit = ability.can( + SpaceCaslAction.Edit, + SpaceCaslSubject.Page, + ); + return this.pageService.getSidebarPages( spaceId, pagination, dto.pageId, user.id, + spaceCanEdit, ); } diff --git a/apps/server/src/core/page/services/page.service.ts b/apps/server/src/core/page/services/page.service.ts index 18586882..370cb4db 100644 --- a/apps/server/src/core/page/services/page.service.ts +++ b/apps/server/src/core/page/services/page.service.ts @@ -183,6 +183,7 @@ export class PageService { pagination: PaginationOptions, pageId?: string, userId?: string, + spaceCanEdit?: boolean, ): Promise & { hasChildren: boolean }>> { let query = this.db .selectFrom('pages') @@ -222,42 +223,53 @@ export class PageService { }); if (userId && result.items.length > 0) { - const pageIds = result.items.map((p: any) => p.id); - - // Single query to get accessible pages with their edit permissions - const accessiblePages = - await this.pagePermissionRepo.filterAccessiblePageIdsWithPermissions( - pageIds, - userId, - ); - - const permissionMap = new Map( - accessiblePages.map((p) => [p.id, p.canEdit]), - ); - - // Filter and add canEdit flag in one pass - result.items = result.items - .filter((p: any) => permissionMap.has(p.id)) - .map((p: any) => ({ - ...p, - canEdit: permissionMap.get(p.id), - })); - - // For pages with hasChildren: true, verify they have accessible children - const pagesWithChildren = result.items.filter((p: any) => p.hasChildren); - if (pagesWithChildren.length > 0) { - const parentIds = pagesWithChildren.map((p: any) => p.id); - const parentsWithAccessibleChildren = - await this.pagePermissionRepo.getParentIdsWithAccessibleChildren( - parentIds, - userId, - ); - const hasAccessibleChildrenSet = new Set(parentsWithAccessibleChildren); + const hasRestrictions = + await this.pagePermissionRepo.hasRestrictedPagesInSpace(spaceId); + if (!hasRestrictions) { result.items = result.items.map((p: any) => ({ ...p, - hasChildren: p.hasChildren && hasAccessibleChildrenSet.has(p.id), + canEdit: spaceCanEdit ?? true, })); + } else { + const pageIds = result.items.map((p: any) => p.id); + + const accessiblePages = + await this.pagePermissionRepo.filterAccessiblePageIdsWithPermissions( + pageIds, + userId, + ); + + const permissionMap = new Map( + accessiblePages.map((p) => [p.id, p.canEdit]), + ); + + result.items = result.items + .filter((p: any) => permissionMap.has(p.id)) + .map((p: any) => ({ + ...p, + canEdit: permissionMap.get(p.id), + })); + + const pagesWithChildren = result.items.filter( + (p: any) => p.hasChildren, + ); + if (pagesWithChildren.length > 0) { + const parentIds = pagesWithChildren.map((p: any) => p.id); + const parentsWithAccessibleChildren = + await this.pagePermissionRepo.getParentIdsWithAccessibleChildren( + parentIds, + userId, + ); + const hasAccessibleChildrenSet = new Set( + parentsWithAccessibleChildren, + ); + + result.items = result.items.map((p: any) => ({ + ...p, + hasChildren: p.hasChildren && hasAccessibleChildrenSet.has(p.id), + })); + } } }