return page permissions

This commit is contained in:
Philipinho
2026-02-22 07:17:54 +00:00
parent e73f34d7e6
commit 56ef3e72d4
2 changed files with 45 additions and 6 deletions
@@ -37,6 +37,34 @@ export class PageAccessService {
} }
} }
/**
* Validate user can view page AND return effective canEdit permission.
* Combines access check + edit permission in a single query pass.
*/
async validateCanViewWithPermissions(
page: Page,
user: User,
): Promise<{ canEdit: boolean }> {
const ability = await this.spaceAbility.createForUser(user, page.spaceId);
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
throw new ForbiddenException();
}
const { hasAnyRestriction, canAccess, canEdit } =
await this.pagePermissionRepo.canUserEditPage(user.id, page.id);
if (hasAnyRestriction && !canAccess) {
throw new ForbiddenException();
}
return {
canEdit: hasAnyRestriction
? canEdit
: ability.can(SpaceCaslAction.Edit, SpaceCaslSubject.Page),
};
}
/** /**
* Validate user can edit page, throws ForbiddenException if not. * Validate user can edit page, throws ForbiddenException if not.
* If page has restrictions: page-level writer permission determines access. * If page has restrictions: page-level writer permission determines access.
+17 -6
View File
@@ -67,7 +67,10 @@ export class PageController {
throw new NotFoundException('Page not found'); throw new NotFoundException('Page not found');
} }
await this.pageAccessService.validateCanView(page, user); const { canEdit } =
await this.pageAccessService.validateCanViewWithPermissions(page, user);
const permissions = { canEdit };
if (dto.format && dto.format !== 'json' && page.content) { if (dto.format && dto.format !== 'json' && page.content) {
const contentOutput = const contentOutput =
@@ -77,10 +80,11 @@ export class PageController {
return { return {
...page, ...page,
content: contentOutput, content: contentOutput,
permissions,
}; };
} }
return page; return { ...page, permissions };
} }
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)
@@ -120,6 +124,11 @@ export class PageController {
createPageDto, createPageDto,
); );
const { canEdit } =
await this.pageAccessService.validateCanViewWithPermissions(page, user);
const permissions = { canEdit };
if ( if (
createPageDto.format && createPageDto.format &&
createPageDto.format !== 'json' && createPageDto.format !== 'json' &&
@@ -129,10 +138,10 @@ export class PageController {
createPageDto.format === 'markdown' createPageDto.format === 'markdown'
? jsonToMarkdown(page.content) ? jsonToMarkdown(page.content)
: jsonToHtml(page.content); : jsonToHtml(page.content);
return { ...page, content: contentOutput }; return { ...page, content: contentOutput, permissions };
} }
return page; return { ...page, permissions };
} }
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)
@@ -152,6 +161,8 @@ export class PageController {
user, user,
); );
const permissions = { canEdit: true };
if ( if (
updatePageDto.format && updatePageDto.format &&
updatePageDto.format !== 'json' && updatePageDto.format !== 'json' &&
@@ -161,10 +172,10 @@ export class PageController {
updatePageDto.format === 'markdown' updatePageDto.format === 'markdown'
? jsonToMarkdown(updatedPage.content) ? jsonToMarkdown(updatedPage.content)
: jsonToHtml(updatedPage.content); : jsonToHtml(updatedPage.content);
return { ...updatedPage, content: contentOutput }; return { ...updatedPage, content: contentOutput, permissions };
} }
return updatedPage; return { ...updatedPage, permissions };
} }
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)