diff --git a/live/package.json b/live/package.json index 91cad6797..7c4b3956a 100644 --- a/live/package.json +++ b/live/package.json @@ -36,9 +36,9 @@ "@types/express": "^4.17.21", "@types/express-ws": "^3.0.4", "@types/node": "^20.14.9", - "tsup": "^7.2.0", "nodemon": "^3.1.0", "ts-node": "^10.9.2", + "tsup": "^7.2.0", "typescript": "^5.4.5" } } diff --git a/live/src/core/helpers/page.ts b/live/src/core/helpers/page.ts new file mode 100644 index 000000000..4e79afe6b --- /dev/null +++ b/live/src/core/helpers/page.ts @@ -0,0 +1,59 @@ +import { getSchema } from "@tiptap/core"; +import { generateHTML, generateJSON } from "@tiptap/html"; +import { prosemirrorJSONToYDoc, yXmlFragmentToProseMirrorRootNode } from "y-prosemirror"; +import * as Y from "yjs" +// plane editor +import { CoreEditorExtensionsWithoutProps, DocumentEditorExtensionsWithoutProps } from "@plane/editor/lib"; + +const DOCUMENT_EDITOR_EXTENSIONS = [ + ...CoreEditorExtensionsWithoutProps, + ...DocumentEditorExtensionsWithoutProps, +]; +const documentEditorSchema = getSchema(DOCUMENT_EDITOR_EXTENSIONS); + +export const getAllDocumentFormatsFromBinaryData = (description: Uint8Array): { + contentBinaryEncoded: string; + contentJSON: object; + contentHTML: string; +} => { + // encode binary description data + const base64Data = Buffer.from(description).toString("base64"); + const yDoc = new Y.Doc(); + Y.applyUpdate(yDoc, description); + // convert to JSON + const type = yDoc.getXmlFragment("default"); + const contentJSON = yXmlFragmentToProseMirrorRootNode( + type, + documentEditorSchema + ).toJSON(); + // convert to HTML + const contentHTML = generateHTML(contentJSON, DOCUMENT_EDITOR_EXTENSIONS); + + return { + contentBinaryEncoded: base64Data, + contentJSON, + contentHTML, + }; +} + +export const getBinaryDataFromHTMLString = (descriptionHTML: string): { + contentBinary: Uint8Array +} => { + // convert HTML to JSON + const contentJSON = generateJSON( + descriptionHTML ?? "
", + DOCUMENT_EDITOR_EXTENSIONS + ); + // convert JSON to Y.Doc format + const transformedData = prosemirrorJSONToYDoc( + documentEditorSchema, + contentJSON, + "default" + ); + // convert Y.Doc to Uint8Array format + const encodedData = Y.encodeStateAsUpdate(transformedData); + + return { + contentBinary: encodedData + } +} \ No newline at end of file diff --git a/live/src/core/lib/authentication.ts b/live/src/core/lib/authentication.ts index 9a746b8f0..222871238 100644 --- a/live/src/core/lib/authentication.ts +++ b/live/src/core/lib/authentication.ts @@ -39,14 +39,15 @@ export const handleAuthentication = async (props: Props) => { "Authentication failed: Incomplete query params. Either workspaceSlug or projectId is missing." ); } - // fetch current user's roles - const workspaceRoles = await userService.getUserAllProjectsRole( + // fetch current user's project membership info + const projectMembershipInfo = await userService.getUserProjectMembership( workspaceSlug, + projectId, cookie ); - const currentProjectRole = workspaceRoles[projectId]; + const projectRole = projectMembershipInfo.role; // make the connection read only for roles lower than a member - if (currentProjectRole < 15) { + if (projectRole < 15) { connection.readOnly = true; } } else { diff --git a/live/src/core/lib/page.ts b/live/src/core/lib/page.ts index b9c206bad..30cf10f41 100644 --- a/live/src/core/lib/page.ts +++ b/live/src/core/lib/page.ts @@ -1,25 +1,9 @@ -import { getSchema } from "@tiptap/core"; -import { generateHTML, generateJSON } from "@tiptap/html"; -import * as Y from "yjs"; -import { - prosemirrorJSONToYDoc, - yXmlFragmentToProseMirrorRootNode, -} from "y-prosemirror"; -// editor -import { - CoreEditorExtensionsWithoutProps, - DocumentEditorExtensionsWithoutProps, -} from "@plane/editor/lib"; +// helpers +import { getAllDocumentFormatsFromBinaryData, getBinaryDataFromHTMLString } from "../../core/helpers/page.js"; // services import { PageService } from "../services/page.service.js"; const pageService = new PageService(); -const DOCUMENT_EDITOR_EXTENSIONS = [ - ...CoreEditorExtensionsWithoutProps, - ...DocumentEditorExtensionsWithoutProps, -]; -const documentEditorSchema = getSchema(DOCUMENT_EDITOR_EXTENSIONS); - export const updatePageDescription = async ( params: URLSearchParams, pageId: string, @@ -35,22 +19,15 @@ export const updatePageDescription = async ( const workspaceSlug = params.get("workspaceSlug")?.toString(); const projectId = params.get("projectId")?.toString(); if (!workspaceSlug || !projectId || !cookie) return; - // encode binary description data - const base64Data = Buffer.from(updatedDescription).toString("base64"); - const yDoc = new Y.Doc(); - Y.applyUpdate(yDoc, updatedDescription); - // convert to JSON - const type = yDoc.getXmlFragment("default"); - const contentJSON = yXmlFragmentToProseMirrorRootNode( - type, - documentEditorSchema - ).toJSON(); - // convert to HTML - const contentHTML = generateHTML(contentJSON, DOCUMENT_EDITOR_EXTENSIONS); + const { + contentBinaryEncoded, + contentHTML, + contentJSON + } = getAllDocumentFormatsFromBinaryData(updatedDescription); try { const payload = { - description_binary: base64Data, + description_binary: contentBinaryEncoded, description_html: contentHTML, description: contentJSON, }; @@ -83,23 +60,8 @@ const fetchDescriptionHTMLAndTransform = async ( pageId, cookie ); - // convert already existing html to json - const contentJSON = generateJSON( - pageDetails.description_html ?? "", - DOCUMENT_EDITOR_EXTENSIONS - ); - // get editor schema from the DOCUMENT_EDITOR_EXTENSIONS array - const schema = getSchema(DOCUMENT_EDITOR_EXTENSIONS); - // convert json to Y.Doc format - const transformedData = prosemirrorJSONToYDoc( - schema, - contentJSON, - "default" - ); - // convert Y.Doc to Uint8Array format - const encodedData = Y.encodeStateAsUpdate(transformedData); - - return encodedData; + const { contentBinary } = getBinaryDataFromHTMLString(pageDetails.description_html ?? "") + return contentBinary; } catch (error) { console.error("Error while transforming from HTML to Uint8Array", error); throw error; diff --git a/live/src/core/services/user.service.ts b/live/src/core/services/user.service.ts index 96b796c94..9afc447d2 100644 --- a/live/src/core/services/user.service.ts +++ b/live/src/core/services/user.service.ts @@ -1,5 +1,5 @@ // types -import type { IUser, IUserProjectsRole } from "@plane/types"; +import type { IProjectMember, IUser } from "@plane/types"; // services import { API_BASE_URL, APIService } from "./api.service.js"; @@ -26,21 +26,36 @@ export class UserService extends APIService { }); } - async getUserAllProjectsRole( + async getUserWorkspaceMembership( workspaceSlug: string, cookie: string - ): Promise