mirror of
https://github.com/docmost/docmost.git
synced 2026-05-16 05:44:04 +08:00
WIP 4
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { PageService } from './services/page.service';
|
||||
import { PagePermissionService } from './services/page-permission.service';
|
||||
import { PageAccessService } from '../page-access/page-access.service';
|
||||
import { CreatePageDto } from './dto/create-page.dto';
|
||||
import { UpdatePageDto } from './dto/update-page.dto';
|
||||
import { MovePageDto, MovePageToSpaceDto } from './dto/move-page.dto';
|
||||
@@ -45,7 +45,7 @@ export class PageController {
|
||||
private readonly pageRepo: PageRepo,
|
||||
private readonly pageHistoryService: PageHistoryService,
|
||||
private readonly spaceAbility: SpaceAbilityFactory,
|
||||
private readonly pagePermissionService: PagePermissionService,
|
||||
private readonly pageAccessService: PageAccessService,
|
||||
) {}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@@ -63,8 +63,7 @@ export class PageController {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
|
||||
// Checks both space-level and page-level permissions
|
||||
await this.pagePermissionService.validateCanView(page, user);
|
||||
await this.pageAccessService.validateCanView(page, user);
|
||||
|
||||
return page;
|
||||
}
|
||||
@@ -76,19 +75,23 @@ export class PageController {
|
||||
@AuthUser() user: User,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
) {
|
||||
const ability = await this.spaceAbility.createForUser(
|
||||
user,
|
||||
createPageDto.spaceId,
|
||||
);
|
||||
if (ability.cannot(SpaceCaslAction.Create, SpaceCaslSubject.Page)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
// If creating under a parent page, check page-level edit permission
|
||||
if (createPageDto.parentPageId) {
|
||||
const parentPage = await this.pageRepo.findById(createPageDto.parentPageId);
|
||||
if (parentPage) {
|
||||
await this.pagePermissionService.validateCanEdit(parentPage, user);
|
||||
// Creating under a parent page - check edit permission on parent
|
||||
const parentPage = await this.pageRepo.findById(
|
||||
createPageDto.parentPageId,
|
||||
);
|
||||
if (!parentPage || parentPage.spaceId !== createPageDto.spaceId) {
|
||||
throw new NotFoundException('Parent page not found');
|
||||
}
|
||||
await this.pageAccessService.validateCanEdit(parentPage, user);
|
||||
} else {
|
||||
// Creating at root level - require space-level permission
|
||||
const ability = await this.spaceAbility.createForUser(
|
||||
user,
|
||||
createPageDto.spaceId,
|
||||
);
|
||||
if (ability.cannot(SpaceCaslAction.Create, SpaceCaslSubject.Page)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +107,7 @@ export class PageController {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
|
||||
// Checks both space-level and page-level permissions
|
||||
await this.pagePermissionService.validateCanEdit(page, user);
|
||||
await this.pageAccessService.validateCanEdit(page, user);
|
||||
|
||||
return this.pageService.update(page, updatePageDto, user.id);
|
||||
}
|
||||
@@ -134,12 +136,8 @@ export class PageController {
|
||||
}
|
||||
await this.pageService.forceDelete(deletePageDto.pageId, workspace.id);
|
||||
} else {
|
||||
// Soft delete requires page manage permissions at space level
|
||||
if (ability.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Page)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
// Also check page-level edit permission
|
||||
await this.pagePermissionService.validateCanEdit(page, user);
|
||||
// User with edit permission can delete
|
||||
await this.pageAccessService.validateCanEdit(page, user);
|
||||
|
||||
await this.pageService.removePage(
|
||||
deletePageDto.pageId,
|
||||
@@ -162,13 +160,17 @@ export class PageController {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
|
||||
//Todo: currently, this means if they are not admins, they need to add a space admin to the page, which is not possible as it was soft-deleted
|
||||
// so page is virtually lost. Fix.
|
||||
const ability = await this.spaceAbility.createForUser(user, page.spaceId);
|
||||
if (ability.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Page)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
//TODO: can users with page level edit, but no space level edit restore pages they can edit?
|
||||
|
||||
// Check page-level edit permission (if restoring to a restricted ancestor)
|
||||
await this.pagePermissionService.validateCanEdit(page, user);
|
||||
await this.pageAccessService.validateCanEdit(page, user);
|
||||
|
||||
await this.pageRepo.restorePage(pageIdDto.pageId, workspace.id);
|
||||
|
||||
@@ -196,6 +198,7 @@ export class PageController {
|
||||
|
||||
return this.pageService.getRecentSpacePages(
|
||||
recentPageDto.spaceId,
|
||||
user.id,
|
||||
pagination,
|
||||
);
|
||||
}
|
||||
@@ -210,6 +213,7 @@ export class PageController {
|
||||
@Body() pagination: PaginationOptions,
|
||||
@AuthUser() user: User,
|
||||
) {
|
||||
//TODO: should space admin see deleted pages they dont have access to?
|
||||
if (deletedPageDto.spaceId) {
|
||||
const ability = await this.spaceAbility.createForUser(
|
||||
user,
|
||||
@@ -227,7 +231,6 @@ export class PageController {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: scope to workspaces
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('/history')
|
||||
async getPageHistory(
|
||||
@@ -240,8 +243,7 @@ export class PageController {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
|
||||
// Checks both space-level and page-level permissions
|
||||
await this.pagePermissionService.validateCanView(page, user);
|
||||
await this.pageAccessService.validateCanView(page, user);
|
||||
|
||||
return this.pageHistoryService.findHistoryByPageId(page.id, pagination);
|
||||
}
|
||||
@@ -263,8 +265,7 @@ export class PageController {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
|
||||
// Checks both space-level and page-level permissions
|
||||
await this.pagePermissionService.validateCanView(page, user);
|
||||
await this.pageAccessService.validateCanView(page, user);
|
||||
|
||||
return history;
|
||||
}
|
||||
@@ -297,7 +298,12 @@ export class PageController {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
return this.pageService.getSidebarPages(spaceId, pagination, dto.pageId, user.id);
|
||||
return this.pageService.getSidebarPages(
|
||||
spaceId,
|
||||
pagination,
|
||||
dto.pageId,
|
||||
user.id,
|
||||
);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@@ -328,9 +334,10 @@ export class PageController {
|
||||
}
|
||||
|
||||
// Check page-level edit permission on the source page
|
||||
await this.pagePermissionService.validateCanEdit(movedPage, user);
|
||||
await this.pageAccessService.validateCanEdit(movedPage, user);
|
||||
|
||||
return this.pageService.movePageToSpace(movedPage, dto.spaceId);
|
||||
// Moves only accessible pages; inaccessible child pages become root pages in original space
|
||||
return this.pageService.movePageToSpace(movedPage, dto.spaceId, user.id);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@@ -342,7 +349,8 @@ export class PageController {
|
||||
}
|
||||
|
||||
// Check page-level view permission on the source page (need to read to copy)
|
||||
await this.pagePermissionService.validateCanView(copiedPage, user);
|
||||
// Inaccessible child branches are automatically skipped during duplication
|
||||
await this.pageAccessService.validateCanView(copiedPage, user);
|
||||
|
||||
// If spaceId is provided, it's a copy to different space
|
||||
if (dto.spaceId) {
|
||||
@@ -382,22 +390,28 @@ export class PageController {
|
||||
throw new NotFoundException('Moved page not found');
|
||||
}
|
||||
|
||||
//TODO: CAN USERS MOVE PAGES IN PORTIONS WHERE THEY HAVE BEEN GRANTED ACCESS TO?
|
||||
// WHAT HAPPENS IF A PAGE WHICH MODES THE PERMISSION IS MOVED TO A DIFFERENT ROOT?
|
||||
// ALSO THE EDIT CHECK BELOW WILL NOT WORK FOR USERS GRANTED EDIT WHO INITIALLY HOLD SPACE LEVEL VIEW
|
||||
// ALSO, SHOULD REALLY PUT IN MIND WHAT SUCH USERS CAN DO IN TERMS OF WHERE THEY MOVE THE PAGE TO
|
||||
|
||||
const ability = await this.spaceAbility.createForUser(
|
||||
user,
|
||||
movedPage.spaceId,
|
||||
);
|
||||
|
||||
if (ability.cannot(SpaceCaslAction.Edit, SpaceCaslSubject.Page)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
// Check page-level edit permission
|
||||
await this.pagePermissionService.validateCanEdit(movedPage, user);
|
||||
await this.pageAccessService.validateCanEdit(movedPage, user);
|
||||
|
||||
// If moving to a new parent, check permission on the target parent
|
||||
if (dto.parentPageId && dto.parentPageId !== movedPage.parentPageId) {
|
||||
const targetParent = await this.pageRepo.findById(dto.parentPageId);
|
||||
if (targetParent) {
|
||||
await this.pagePermissionService.validateCanEdit(targetParent, user);
|
||||
await this.pageAccessService.validateCanEdit(targetParent, user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,8 +426,7 @@ export class PageController {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
|
||||
// Checks both space-level and page-level permissions
|
||||
await this.pagePermissionService.validateCanView(page, user);
|
||||
await this.pageAccessService.validateCanView(page, user);
|
||||
|
||||
return this.pageService.getPageBreadCrumbs(page.id);
|
||||
}
|
||||
|
||||
@@ -428,38 +428,11 @@ export class PagePermissionService {
|
||||
pageIds: string[],
|
||||
userId: string,
|
||||
): Promise<string[]> {
|
||||
return this.pagePermissionRepo.filterAccessiblePageIds(pageIds, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate user can view page, throws ForbiddenException if not.
|
||||
* Checks both space-level and page-level permissions.
|
||||
*/
|
||||
async validateCanView(page: Page, user: User): Promise<void> {
|
||||
const ability = await this.spaceAbility.createForUser(user, page.spaceId);
|
||||
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
const canView = await this.canViewPage(user.id, page.id);
|
||||
if (!canView) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate user can edit page, throws ForbiddenException if not.
|
||||
* Checks both space-level and page-level permissions.
|
||||
*/
|
||||
async validateCanEdit(page: Page, user: User): Promise<void> {
|
||||
const ability = await this.spaceAbility.createForUser(user, page.spaceId);
|
||||
if (ability.cannot(SpaceCaslAction.Edit, SpaceCaslSubject.Page)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
const canEdit = await this.canEditPage(user.id, page.id);
|
||||
if (!canEdit) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
const results =
|
||||
await this.pagePermissionRepo.filterAccessiblePageIdsWithPermissions(
|
||||
pageIds,
|
||||
userId,
|
||||
);
|
||||
return results.map((r) => r.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,61 @@ export class PageService {
|
||||
private eventEmitter: EventEmitter2,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Filters a list of pages to only those accessible to the user while maintaining tree integrity.
|
||||
* A page is included only if:
|
||||
* 1. The user has access to it
|
||||
* 2. Its parent is also included (or it's the root page)
|
||||
* This ensures that if a middle page is inaccessible, its entire subtree is excluded.
|
||||
*/
|
||||
private async filterAccessibleTreePages<T extends { id: string; parentPageId: string | null }>(
|
||||
pages: T[],
|
||||
rootPageId: string,
|
||||
userId: string,
|
||||
): Promise<T[]> {
|
||||
if (pages.length === 0) return [];
|
||||
|
||||
const pageIds = pages.map((p) => p.id);
|
||||
const accessiblePages =
|
||||
await this.pagePermissionRepo.filterAccessiblePageIdsWithPermissions(
|
||||
pageIds,
|
||||
userId,
|
||||
);
|
||||
const accessibleSet = new Set(accessiblePages.map((p) => p.id));
|
||||
|
||||
// Build a map for quick lookup
|
||||
const pageMap = new Map(pages.map((p) => [p.id, p]));
|
||||
|
||||
// Prune: include a page only if it's accessible AND its parent chain to root is included
|
||||
const includedIds = new Set<string>();
|
||||
|
||||
// Process pages in a way that ensures parents are processed before children
|
||||
// We do this by iterating until no more pages can be added
|
||||
let changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (const page of pages) {
|
||||
if (includedIds.has(page.id)) continue;
|
||||
if (!accessibleSet.has(page.id)) continue;
|
||||
|
||||
// Root page: include if accessible
|
||||
if (page.id === rootPageId) {
|
||||
includedIds.add(page.id);
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Non-root: include if parent is already included
|
||||
if (page.parentPageId && includedIds.has(page.parentPageId)) {
|
||||
includedIds.add(page.id);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pages.filter((p) => includedIds.has(p.id));
|
||||
}
|
||||
|
||||
async findById(
|
||||
pageId: string,
|
||||
includeContent?: boolean,
|
||||
@@ -169,7 +224,7 @@ export class PageService {
|
||||
page.id,
|
||||
);
|
||||
|
||||
return await this.pageRepo.findById(page.id, {
|
||||
return this.pageRepo.findById(page.id, {
|
||||
includeSpace: true,
|
||||
includeContent: true,
|
||||
includeCreator: true,
|
||||
@@ -197,12 +252,7 @@ export class PageService {
|
||||
'creatorId',
|
||||
'deletedAt',
|
||||
])
|
||||
.$if(Boolean(userId), (qb) =>
|
||||
qb.select((eb) => this.pageRepo.withHasChildrenV2(eb, userId)),
|
||||
)
|
||||
//.$if(!userId, (qb) =>
|
||||
// qb.select((eb) => this.pageRepo.withHasChildren(eb)),
|
||||
// )
|
||||
.select((eb) => this.pageRepo.withHasChildren(eb))
|
||||
.orderBy('position', (ob) => ob.collate('C').asc())
|
||||
.where('deletedAt', 'is', null)
|
||||
.where('spaceId', '=', spaceId);
|
||||
@@ -218,22 +268,78 @@ export class PageService {
|
||||
perPage: 250,
|
||||
});
|
||||
|
||||
// Filter by page-level permissions
|
||||
if (userId && result.items.length > 0) {
|
||||
const pageIds = result.items.map((p: any) => p.id);
|
||||
const accessiblePageIds = await this.pagePermissionRepo.filterAccessiblePageIds(
|
||||
pageIds,
|
||||
userId,
|
||||
|
||||
// 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]),
|
||||
);
|
||||
const accessibleSet = new Set(accessiblePageIds);
|
||||
result.items = result.items.filter((p: any) => accessibleSet.has(p.id));
|
||||
|
||||
// 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);
|
||||
|
||||
result.items = result.items.map((p: any) => ({
|
||||
...p,
|
||||
hasChildren: p.hasChildren && hasAccessibleChildrenSet.has(p.id),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async movePageToSpace(rootPage: Page, spaceId: string) {
|
||||
async movePageToSpace(rootPage: Page, spaceId: string, userId: string) {
|
||||
const allPages = await this.pageRepo.getPageAndDescendants(rootPage.id, {
|
||||
includeContent: false,
|
||||
});
|
||||
|
||||
// Filter to only accessible pages while maintaining tree integrity
|
||||
const accessiblePages = await this.filterAccessibleTreePages(
|
||||
allPages,
|
||||
rootPage.id,
|
||||
userId,
|
||||
);
|
||||
const accessibleIds = new Set(accessiblePages.map((p) => p.id));
|
||||
|
||||
// Find inaccessible pages whose parent is being moved - these need to be orphaned
|
||||
const pagesToOrphan = allPages.filter(
|
||||
(p) => !accessibleIds.has(p.id) && p.parentPageId && accessibleIds.has(p.parentPageId),
|
||||
);
|
||||
|
||||
await executeTx(this.db, async (trx) => {
|
||||
// Orphan inaccessible child pages (make them root pages in original space)
|
||||
for (const page of pagesToOrphan) {
|
||||
const orphanPosition = await this.nextPagePosition(rootPage.spaceId, null);
|
||||
await this.pageRepo.updatePage(
|
||||
{ parentPageId: null, position: orphanPosition },
|
||||
page.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
// Update root page
|
||||
const nextPosition = await this.nextPagePosition(spaceId);
|
||||
await this.pageRepo.updatePage(
|
||||
@@ -241,44 +347,50 @@ export class PageService {
|
||||
rootPage.id,
|
||||
trx,
|
||||
);
|
||||
const pageIds = await this.pageRepo
|
||||
.getPageAndDescendants(rootPage.id, { includeContent: false })
|
||||
.then((pages) => pages.map((page) => page.id));
|
||||
// The first id is the root page id
|
||||
if (pageIds.length > 1) {
|
||||
// Update sub pages
|
||||
|
||||
const pageIdsToMove = accessiblePages.map((p) => p.id);
|
||||
|
||||
if (pageIdsToMove.length > 1) {
|
||||
// Update sub pages (all accessible pages except root)
|
||||
await this.pageRepo.updatePages(
|
||||
{ spaceId },
|
||||
pageIds.filter((id) => id !== rootPage.id),
|
||||
pageIdsToMove.filter((id) => id !== rootPage.id),
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
if (pageIds.length > 0) {
|
||||
if (pageIdsToMove.length > 0) {
|
||||
// Clear page-level permissions - moved pages inherit destination space permissions
|
||||
// (page_permissions cascade deletes via foreign key)
|
||||
await trx
|
||||
.deleteFrom('pageAccess')
|
||||
.where('pageId', 'in', pageIdsToMove)
|
||||
.execute();
|
||||
|
||||
// update spaceId in shares
|
||||
await trx
|
||||
.updateTable('shares')
|
||||
.set({ spaceId: spaceId })
|
||||
.where('pageId', 'in', pageIds)
|
||||
.where('pageId', 'in', pageIdsToMove)
|
||||
.execute();
|
||||
|
||||
// Update comments
|
||||
await trx
|
||||
.updateTable('comments')
|
||||
.set({ spaceId: spaceId })
|
||||
.where('pageId', 'in', pageIds)
|
||||
.where('pageId', 'in', pageIdsToMove)
|
||||
.execute();
|
||||
|
||||
// Update attachments
|
||||
await this.attachmentRepo.updateAttachmentsByPageId(
|
||||
{ spaceId },
|
||||
pageIds,
|
||||
pageIdsToMove,
|
||||
trx,
|
||||
);
|
||||
|
||||
await this.aiQueue.add(QueueJob.PAGE_MOVED_TO_SPACE, {
|
||||
pageId: pageIds,
|
||||
workspaceId: rootPage.workspaceId
|
||||
pageId: pageIdsToMove,
|
||||
workspaceId: rootPage.workspaceId,
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -303,10 +415,17 @@ export class PageService {
|
||||
nextPosition = await this.nextPagePosition(spaceId);
|
||||
}
|
||||
|
||||
const pages = await this.pageRepo.getPageAndDescendants(rootPage.id, {
|
||||
const allPages = await this.pageRepo.getPageAndDescendants(rootPage.id, {
|
||||
includeContent: true,
|
||||
});
|
||||
|
||||
// Filter to only accessible pages while maintaining tree integrity
|
||||
const pages = await this.filterAccessibleTreePages(
|
||||
allPages,
|
||||
rootPage.id,
|
||||
authUser.id,
|
||||
);
|
||||
|
||||
const pageMap = new Map<string, CopyPageMapEntry>();
|
||||
pages.forEach((page) => {
|
||||
pageMap.set(page.id, {
|
||||
@@ -406,9 +525,14 @@ export class PageService {
|
||||
workspaceId: page.workspaceId,
|
||||
creatorId: authUser.id,
|
||||
lastUpdatedById: authUser.id,
|
||||
parentPageId: page.id === rootPage.id
|
||||
? (isDuplicateInSameSpace ? rootPage.parentPageId : null)
|
||||
: (page.parentPageId ? pageMap.get(page.parentPageId)?.newPageId : null),
|
||||
parentPageId:
|
||||
page.id === rootPage.id
|
||||
? isDuplicateInSameSpace
|
||||
? rootPage.parentPageId
|
||||
: null
|
||||
: page.parentPageId
|
||||
? pageMap.get(page.parentPageId)?.newPageId
|
||||
: null,
|
||||
};
|
||||
}),
|
||||
);
|
||||
@@ -587,16 +711,43 @@ export class PageService {
|
||||
|
||||
async getRecentSpacePages(
|
||||
spaceId: string,
|
||||
userId: string,
|
||||
pagination: PaginationOptions,
|
||||
): Promise<PaginationResult<Page>> {
|
||||
return await this.pageRepo.getRecentPagesInSpace(spaceId, pagination);
|
||||
const result = await this.pageRepo.getRecentPagesInSpace(spaceId, pagination);
|
||||
|
||||
if (result.items.length > 0) {
|
||||
const pageIds = result.items.map((p) => p.id);
|
||||
const accessiblePages =
|
||||
await this.pagePermissionRepo.filterAccessiblePageIdsWithPermissions(
|
||||
pageIds,
|
||||
userId,
|
||||
);
|
||||
const accessibleSet = new Set(accessiblePages.map((p) => p.id));
|
||||
result.items = result.items.filter((p) => accessibleSet.has(p.id));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async getRecentPages(
|
||||
userId: string,
|
||||
pagination: PaginationOptions,
|
||||
): Promise<PaginationResult<Page>> {
|
||||
return await this.pageRepo.getRecentPages(userId, pagination);
|
||||
const result = await this.pageRepo.getRecentPages(userId, pagination);
|
||||
|
||||
if (result.items.length > 0) {
|
||||
const pageIds = result.items.map((p) => p.id);
|
||||
const accessiblePages =
|
||||
await this.pagePermissionRepo.filterAccessiblePageIdsWithPermissions(
|
||||
pageIds,
|
||||
userId,
|
||||
);
|
||||
const accessibleSet = new Set(accessiblePages.map((p) => p.id));
|
||||
result.items = result.items.filter((p) => accessibleSet.has(p.id));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async getDeletedSpacePages(
|
||||
|
||||
Reference in New Issue
Block a user