This commit is contained in:
Philipinho
2025-04-10 23:47:26 +01:00
parent 4f52d32bef
commit 16a253ec40
9 changed files with 141 additions and 48 deletions

View File

@ -1,6 +1,9 @@
import { IsString } from 'class-validator';
import { IsBoolean, IsString } from 'class-validator';
export class CreateShareDto {
@IsString()
pageId: string;
@IsBoolean()
includeSubPages: boolean;
}

View File

@ -12,12 +12,14 @@ import { TokenService } from '../auth/services/token.service';
import { jsonToNode } from '../../collaboration/collaboration.util';
import {
getAttachmentIds,
getProsemirrorContent,
isAttachmentNode,
} from '../../common/helpers/prosemirror/utils';
import { Node } from '@tiptap/pm/model';
import { ShareRepo } from '@docmost/db/repos/share/share.repo';
import { updateAttachmentAttr } from './share.util';
import { Page } from '@docmost/db/types/entity.types';
import { validate as isValidUUID } from 'uuid';
@Injectable()
export class ShareService {
@ -59,7 +61,21 @@ export class ShareService {
throw new NotFoundException('Share not found');
}
const page = await this.pageRepo.findById(share.pageId, {
let targetPageId = share.pageId;
if (dto.pageId && dto.pageId !== share.pageId) {
// Check if dto.pageId is a descendant of the shared page.
const isDescendant = await this.getShareAncestorPage(
share.pageId,
dto.pageId,
);
if (isDescendant) {
targetPageId = dto.pageId;
} else {
throw new NotFoundException(`Shared page not found`);
}
}
const page = await this.pageRepo.findById(targetPageId, {
includeContent: true,
includeCreator: true,
});
@ -73,8 +89,74 @@ export class ShareService {
return page;
}
async getShareAncestorPage(
ancestorPageId: string,
childPageId: string,
): Promise<any> {
let ancestor = null;
try {
ancestor = await this.db
.withRecursive('page_ancestors', (db) =>
db
.selectFrom('pages')
.select([
'id',
'slugId',
'title',
'parentPageId',
'spaceId',
(eb) =>
eb
.case()
.when(eb.ref('id'), '=', ancestorPageId)
.then(true)
.else(false)
.end()
.as('found'),
])
.where(
!isValidUUID(childPageId) ? 'slugId' : 'id',
'=',
childPageId,
)
.unionAll((exp) =>
exp
.selectFrom('pages as p')
.select([
'p.id',
'p.slugId',
'p.title',
'p.parentPageId',
'p.spaceId',
(eb) =>
eb
.case()
.when(eb.ref('p.id'), '=', ancestorPageId)
.then(true)
.else(false)
.end()
.as('found'),
])
.innerJoin('page_ancestors as pa', 'pa.parentPageId', 'p.id')
// Continue recursing only when the target ancestor hasn't been found on that branch.
.where('pa.found', '=', false),
),
)
.selectFrom('page_ancestors')
.selectAll()
.where('found', '=', true)
.limit(1)
.executeTakeFirst();
} catch (err) {
// empty
}
return ancestor;
}
async updatePublicAttachments(page: Page): Promise<any> {
const attachmentIds = getAttachmentIds(page.content);
const prosemirrorJson = getProsemirrorContent(page.content);
const attachmentIds = getAttachmentIds(prosemirrorJson);
const attachmentMap = new Map<string, string>();
await Promise.all(
@ -88,7 +170,7 @@ export class ShareService {
}),
);
const doc = jsonToNode(page.content as any);
const doc = jsonToNode(prosemirrorJson);
doc?.descendants((node: Node) => {
if (!isAttachmentNode(node.type.name)) return;