refactor(html-embed): extract the admin-gate strip into one tested helper (#90)
The 4-step html-embed gate (feature-enabled AND role-allowed -> stripHtmlEmbedNodes)
was replicated across call-sites, pinned only by brittle source-regex tests. Add
stripHtmlEmbedIfNotAllowed(json, {featureEnabled, role, onStrip}) and migrate the
5 plain strip-all sites (collab handler, page create+duplicate, both import paths,
transclusion) to it, each keeping its own feature/role resolve + log via onStrip.
Left the 2 sites with different semantics: persistence.extension (#29 preserve-
admin) and share.service (feature-only kill-switch, no role gate). Real unit tests
replace the regex pins; behavior identical.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -32,10 +32,8 @@ import {
|
||||
removeMarkTypeFromDoc,
|
||||
} from '../../../common/helpers/prosemirror/utils';
|
||||
import {
|
||||
hasHtmlEmbedNode,
|
||||
htmlEmbedAllowed,
|
||||
isHtmlEmbedFeatureEnabled,
|
||||
stripHtmlEmbedNodes,
|
||||
stripHtmlEmbedIfNotAllowed,
|
||||
} from '../../../common/helpers/prosemirror/html-embed.util';
|
||||
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
||||
import {
|
||||
@@ -157,15 +155,14 @@ export class PageService {
|
||||
const htmlEmbedEnabled = isHtmlEmbedFeatureEnabled(
|
||||
(await this.workspaceRepo.findById(workspaceId))?.settings,
|
||||
);
|
||||
if (
|
||||
!htmlEmbedAllowed(htmlEmbedEnabled, callerRole) &&
|
||||
hasHtmlEmbedNode(prosemirrorJson)
|
||||
) {
|
||||
this.logger.warn(
|
||||
`Stripping htmlEmbed node(s) from page creation by user ${userId} (space ${createPageDto.spaceId})`,
|
||||
);
|
||||
prosemirrorJson = stripHtmlEmbedNodes(prosemirrorJson);
|
||||
}
|
||||
prosemirrorJson = stripHtmlEmbedIfNotAllowed(prosemirrorJson, {
|
||||
featureEnabled: htmlEmbedEnabled,
|
||||
role: callerRole,
|
||||
onStrip: () =>
|
||||
this.logger.warn(
|
||||
`Stripping htmlEmbed node(s) from page creation by user ${userId} (space ${createPageDto.spaceId})`,
|
||||
),
|
||||
});
|
||||
|
||||
content = prosemirrorJson;
|
||||
textContent = jsonToText(prosemirrorJson);
|
||||
@@ -782,15 +779,14 @@ export class PageService {
|
||||
// that contains an embed into a new page authored by them. Strip every
|
||||
// htmlEmbed node from each duplicated page when the duplicating user is
|
||||
// not an admin, BEFORE computing textContent/ydoc/insert.
|
||||
if (
|
||||
!htmlEmbedAllowed(htmlEmbedEnabled, authUser.role) &&
|
||||
hasHtmlEmbedNode(prosemirrorJson)
|
||||
) {
|
||||
this.logger.warn(
|
||||
`Stripping htmlEmbed node(s) from page duplication by user ${authUser.id} (source page ${page.id})`,
|
||||
);
|
||||
prosemirrorJson = stripHtmlEmbedNodes(prosemirrorJson);
|
||||
}
|
||||
prosemirrorJson = stripHtmlEmbedIfNotAllowed(prosemirrorJson, {
|
||||
featureEnabled: htmlEmbedEnabled,
|
||||
role: authUser.role,
|
||||
onStrip: () =>
|
||||
this.logger.warn(
|
||||
`Stripping htmlEmbed node(s) from page duplication by user ${authUser.id} (source page ${page.id})`,
|
||||
),
|
||||
});
|
||||
|
||||
// Add "Copy of " prefix to the root page title only for duplicates in same space
|
||||
let title = page.title;
|
||||
|
||||
@@ -34,10 +34,8 @@ import { jsonToNode } from '../../../collaboration/collaboration.util';
|
||||
import { Page, User } from '@docmost/db/types/entity.types';
|
||||
import { PageAccessService } from '../page-access/page-access.service';
|
||||
import {
|
||||
hasHtmlEmbedNode,
|
||||
htmlEmbedAllowed,
|
||||
isHtmlEmbedFeatureEnabled,
|
||||
stripHtmlEmbedNodes,
|
||||
stripHtmlEmbedIfNotAllowed,
|
||||
} from '../../../common/helpers/prosemirror/html-embed.util';
|
||||
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
||||
|
||||
@@ -774,12 +772,14 @@ export class TransclusionService {
|
||||
const htmlEmbedEnabled = isHtmlEmbedFeatureEnabled(
|
||||
(await this.workspaceRepo.findById(user.workspaceId))?.settings,
|
||||
);
|
||||
if (!htmlEmbedAllowed(htmlEmbedEnabled, user.role) && hasHtmlEmbedNode(content)) {
|
||||
this.logger.warn(
|
||||
`Stripping htmlEmbed node(s) from transclusion unsync by user ${user.id} (reference page ${referencePageId}, source page ${sourcePageId})`,
|
||||
);
|
||||
content = stripHtmlEmbedNodes(content);
|
||||
}
|
||||
content = stripHtmlEmbedIfNotAllowed(content, {
|
||||
featureEnabled: htmlEmbedEnabled,
|
||||
role: user.role,
|
||||
onStrip: () =>
|
||||
this.logger.warn(
|
||||
`Stripping htmlEmbed node(s) from transclusion unsync by user ${user.id} (reference page ${referencePageId}, source page ${sourcePageId})`,
|
||||
),
|
||||
});
|
||||
|
||||
return { content };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user