mirror of
https://github.com/docmost/docmost.git
synced 2026-05-17 23:14:07 +08:00
Sidebar tree socket permissions
This commit is contained in:
@@ -32,6 +32,8 @@ import {
|
||||
CursorPaginationResult,
|
||||
emptyCursorPaginationResult,
|
||||
} from '@docmost/db/pagination/cursor-pagination';
|
||||
import { WsService } from '../../../ws/ws.service';
|
||||
import { WsTreeService } from '../../../ws/ws-tree.service';
|
||||
|
||||
export type PageRestrictionInfo = {
|
||||
id: string;
|
||||
@@ -51,6 +53,8 @@ export class PagePermissionService {
|
||||
private pagePermissionRepo: PagePermissionRepo,
|
||||
private pageRepo: PageRepo,
|
||||
private spaceAbility: SpaceAbilityFactory,
|
||||
private wsService: WsService,
|
||||
private wsTreeService: WsTreeService,
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
) {}
|
||||
|
||||
@@ -95,6 +99,9 @@ export class PagePermissionService {
|
||||
trx,
|
||||
);
|
||||
});
|
||||
|
||||
await this.wsService.invalidateSpaceRestrictionCache(page.spaceId);
|
||||
await this.wsTreeService.notifyPageRestricted(page, authUser.id);
|
||||
}
|
||||
|
||||
async addPagePermissions(
|
||||
@@ -181,6 +188,23 @@ export class PagePermissionService {
|
||||
|
||||
if (permissionsToAdd.length > 0) {
|
||||
await this.pagePermissionRepo.insertPagePermissions(permissionsToAdd);
|
||||
|
||||
const notifyUserIds = validUsers.map((u) => u.id);
|
||||
|
||||
if (validGroups.length > 0) {
|
||||
const groupMembers = await this.db
|
||||
.selectFrom('groupUsers')
|
||||
.select('userId')
|
||||
.where(
|
||||
'groupId',
|
||||
'in',
|
||||
validGroups.map((g) => g.id),
|
||||
)
|
||||
.execute();
|
||||
notifyUserIds.push(...groupMembers.map((m) => m.userId));
|
||||
}
|
||||
|
||||
await this.wsTreeService.notifyPermissionGranted(page, notifyUserIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,6 +338,8 @@ export class PagePermissionService {
|
||||
}
|
||||
|
||||
await this.pagePermissionRepo.deletePageAccess(pageId);
|
||||
|
||||
await this.wsService.invalidateSpaceRestrictionCache(page.spaceId);
|
||||
}
|
||||
|
||||
async getPagePermissions(
|
||||
|
||||
@@ -217,7 +217,11 @@ export class PageService {
|
||||
cursor: pagination.cursor,
|
||||
beforeCursor: pagination.beforeCursor,
|
||||
fields: [
|
||||
{ expression: 'position', direction: 'asc', orderModifier: (ob) => ob.collate('C').asc() },
|
||||
{
|
||||
expression: 'position',
|
||||
direction: 'asc',
|
||||
orderModifier: (ob) => ob.collate('C').asc(),
|
||||
},
|
||||
{ expression: 'id', direction: 'asc' },
|
||||
],
|
||||
parseCursor: (cursor) => ({
|
||||
@@ -296,13 +300,19 @@ export class PageService {
|
||||
|
||||
// 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),
|
||||
(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);
|
||||
const orphanPosition = await this.nextPagePosition(
|
||||
rootPage.spaceId,
|
||||
null,
|
||||
);
|
||||
await this.pageRepo.updatePage(
|
||||
{ parentPageId: null, position: orphanPosition },
|
||||
page.id,
|
||||
@@ -689,7 +699,10 @@ export class PageService {
|
||||
userId: string,
|
||||
pagination: PaginationOptions,
|
||||
): Promise<CursorPaginationResult<Page>> {
|
||||
const result = 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);
|
||||
@@ -814,7 +827,9 @@ export class PageService {
|
||||
* 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 }>(
|
||||
private async filterAccessibleTreePages<
|
||||
T extends { id: string; parentPageId: string | null },
|
||||
>(
|
||||
pages: T[],
|
||||
rootPageId: string,
|
||||
userId: string,
|
||||
@@ -823,12 +838,13 @@ export class PageService {
|
||||
if (pages.length === 0) return [];
|
||||
|
||||
const pageIds = pages.map((p) => p.id);
|
||||
const accessibleIds =
|
||||
await this.pagePermissionRepo.filterAccessiblePageIds({
|
||||
const accessibleIds = await this.pagePermissionRepo.filterAccessiblePageIds(
|
||||
{
|
||||
pageIds,
|
||||
userId,
|
||||
spaceId,
|
||||
});
|
||||
},
|
||||
);
|
||||
const accessibleSet = new Set(accessibleIds);
|
||||
|
||||
// Prune: include a page only if it's accessible AND its parent chain to root is included
|
||||
|
||||
Reference in New Issue
Block a user