mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-27 19:00:02 +00:00
UBERF-5044 Pass workspace name as part of collaborative document name (#4424)
Signed-off-by: Alexander Onnikov <alexander.onnikov@xored.com>
This commit is contained in:
parent
b0c64803bb
commit
6882c75775
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import { Class, Doc, Hierarchy, Markup, Ref, concatLink } from '@hcengineering/core'
|
import { Class, Doc, Hierarchy, Markup, Ref, WorkspaceId, concatLink } from '@hcengineering/core'
|
||||||
import { minioDocumentId, mongodbDocumentId } from './utils'
|
import { minioDocumentId, mongodbDocumentId } from './utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,25 +27,32 @@ export interface CollaboratorClient {
|
|||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export function getClient (hierarchy: Hierarchy, token: string, collaboratorUrl: string): CollaboratorClient {
|
export function getClient (
|
||||||
return new CollaboratorClientImpl(hierarchy, token, collaboratorUrl)
|
hierarchy: Hierarchy,
|
||||||
|
workspaceId: WorkspaceId,
|
||||||
|
token: string,
|
||||||
|
collaboratorUrl: string
|
||||||
|
): CollaboratorClient {
|
||||||
|
return new CollaboratorClientImpl(hierarchy, workspaceId, token, collaboratorUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
class CollaboratorClientImpl implements CollaboratorClient {
|
class CollaboratorClientImpl implements CollaboratorClient {
|
||||||
constructor (
|
constructor (
|
||||||
private readonly hierarchy: Hierarchy,
|
private readonly hierarchy: Hierarchy,
|
||||||
|
private readonly workspace: WorkspaceId,
|
||||||
private readonly token: string,
|
private readonly token: string,
|
||||||
private readonly collaboratorUrl: string
|
private readonly collaboratorUrl: string
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
initialContentId (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string): string {
|
initialContentId (workspace: string, classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string): string {
|
||||||
const domain = this.hierarchy.getDomain(classId)
|
const domain = this.hierarchy.getDomain(classId)
|
||||||
return mongodbDocumentId(domain, docId, attribute)
|
return mongodbDocumentId(workspace, domain, docId, attribute)
|
||||||
}
|
}
|
||||||
|
|
||||||
async get (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string): Promise<Markup> {
|
async get (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string): Promise<Markup> {
|
||||||
const documentId = encodeURIComponent(minioDocumentId(docId, attribute))
|
const workspace = this.workspace.name
|
||||||
const initialContentId = encodeURIComponent(this.initialContentId(classId, docId, attribute))
|
const documentId = encodeURIComponent(minioDocumentId(workspace, docId, attribute))
|
||||||
|
const initialContentId = encodeURIComponent(this.initialContentId(workspace, classId, docId, attribute))
|
||||||
attribute = encodeURIComponent(attribute)
|
attribute = encodeURIComponent(attribute)
|
||||||
|
|
||||||
const url = concatLink(
|
const url = concatLink(
|
||||||
@ -65,8 +72,9 @@ class CollaboratorClientImpl implements CollaboratorClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string, value: Markup): Promise<void> {
|
async update (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string, value: Markup): Promise<void> {
|
||||||
const documentId = encodeURIComponent(minioDocumentId(docId, attribute))
|
const workspace = this.workspace.name
|
||||||
const initialContentId = encodeURIComponent(this.initialContentId(classId, docId, attribute))
|
const documentId = encodeURIComponent(minioDocumentId(workspace, docId, attribute))
|
||||||
|
const initialContentId = encodeURIComponent(this.initialContentId(workspace, classId, docId, attribute))
|
||||||
attribute = encodeURIComponent(attribute)
|
attribute = encodeURIComponent(attribute)
|
||||||
|
|
||||||
const url = concatLink(
|
const url = concatLink(
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
import { Doc, Domain, Ref } from '@hcengineering/core'
|
import { Doc, Domain, Ref } from '@hcengineering/core'
|
||||||
|
|
||||||
export function minioDocumentId (docId: Ref<Doc>, attribute?: string): string {
|
export function minioDocumentId (workspace: string, docId: Ref<Doc>, attribute?: string): string {
|
||||||
return attribute !== undefined ? `minio://${docId}%${attribute}` : `minio://${docId}`
|
return attribute !== undefined ? `minio://${workspace}/${docId}%${attribute}` : `minio://${workspace}/${docId}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mongodbDocumentId (domain: Domain, docId: Ref<Doc>, attribute: string): string {
|
export function mongodbDocumentId (workspace: string, domain: Domain, docId: Ref<Doc>, attribute: string): string {
|
||||||
return `mongodb://${domain}/${docId}/${attribute}`
|
return `mongodb://${workspace}/${domain}/${docId}/${attribute}`
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { type CollaboratorClient, getClient as getCollaborator } from '@hcengineering/collaborator-client'
|
import { type CollaboratorClient, getClient as getCollaborator } from '@hcengineering/collaborator-client'
|
||||||
import type { Class, Doc, Markup, Ref } from '@hcengineering/core'
|
import { getWorkspaceId, type Class, type Doc, type Markup, type Ref } from '@hcengineering/core'
|
||||||
import { getMetadata } from '@hcengineering/platform'
|
import { getMetadata } from '@hcengineering/platform'
|
||||||
|
import { getCurrentLocation } from '@hcengineering/ui'
|
||||||
|
|
||||||
import { getClient } from '.'
|
import { getClient } from '.'
|
||||||
import presentation from './plugin'
|
import presentation from './plugin'
|
||||||
@ -24,11 +25,12 @@ import presentation from './plugin'
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export function getCollaboratorClient (): CollaboratorClient {
|
export function getCollaboratorClient (): CollaboratorClient {
|
||||||
|
const workspaceId = getWorkspaceId(getCurrentLocation().path[1] ?? '')
|
||||||
const hierarchy = getClient().getHierarchy()
|
const hierarchy = getClient().getHierarchy()
|
||||||
const token = getMetadata(presentation.metadata.Token) ?? ''
|
const token = getMetadata(presentation.metadata.Token) ?? ''
|
||||||
const collaboratorURL = getMetadata(presentation.metadata.CollaboratorUrl) ?? ''
|
const collaboratorURL = getMetadata(presentation.metadata.CollaboratorUrl) ?? ''
|
||||||
|
|
||||||
return getCollaborator(hierarchy, token, collaboratorURL)
|
return getCollaborator(hierarchy, workspaceId, token, collaboratorURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
return commandHandler
|
return commandHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
export function takeSnapshot (snapshotId: string): void {
|
export function takeSnapshot (snapshotId: DocumentId): void {
|
||||||
copyDocumentContent(documentId, snapshotId, { provider: remoteProvider }, initialContentId)
|
copyDocumentContent(documentId, snapshotId, { provider: remoteProvider }, initialContentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
return collaborativeEditor?.commands()
|
return collaborativeEditor?.commands()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function takeSnapshot (snapshotId: string): void {
|
export function takeSnapshot (snapshotId: DocumentId): void {
|
||||||
collaborativeEditor?.takeSnapshot(snapshotId)
|
collaborativeEditor?.takeSnapshot(snapshotId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ export { ImageExtension, type ImageOptions } from './components/extension/imageE
|
|||||||
export { TodoItemExtension, TodoListExtension } from './components/extension/todo'
|
export { TodoItemExtension, TodoListExtension } from './components/extension/todo'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
type DocumentId,
|
||||||
TiptapCollabProvider,
|
TiptapCollabProvider,
|
||||||
type TiptapCollabProviderConfiguration,
|
type TiptapCollabProviderConfiguration,
|
||||||
createTiptapCollaborationData
|
createTiptapCollaborationData
|
||||||
|
@ -44,6 +44,10 @@ export class MinioProvider extends Observable<EVENTS> {
|
|||||||
|
|
||||||
if (name.startsWith('minio://')) {
|
if (name.startsWith('minio://')) {
|
||||||
name = name.split('://', 2)[1]
|
name = name.split('://', 2)[1]
|
||||||
|
if (name.includes('/')) {
|
||||||
|
// drop workspace part
|
||||||
|
name = name.split('/', 2)[1]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchContent(doc, name).then(() => {
|
void fetchContent(doc, name).then(() => {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
import { Doc as Ydoc } from 'yjs'
|
import { Doc as Ydoc } from 'yjs'
|
||||||
import { HocuspocusProvider, type HocuspocusProviderConfiguration } from '@hocuspocus/provider'
|
import { HocuspocusProvider, type HocuspocusProviderConfiguration } from '@hocuspocus/provider'
|
||||||
|
|
||||||
export type DocumentId = string
|
export type DocumentId = string & { __documentId: true }
|
||||||
|
|
||||||
export type TiptapCollabProviderConfiguration = HocuspocusProviderConfiguration &
|
export type TiptapCollabProviderConfiguration = HocuspocusProviderConfiguration &
|
||||||
Required<Pick<HocuspocusProviderConfiguration, 'token'>> &
|
Required<Pick<HocuspocusProviderConfiguration, 'token'>> &
|
||||||
|
@ -15,18 +15,28 @@
|
|||||||
|
|
||||||
import type { Doc, Ref } from '@hcengineering/core'
|
import type { Doc, Ref } from '@hcengineering/core'
|
||||||
import { type KeyedAttribute, getClient } from '@hcengineering/presentation'
|
import { type KeyedAttribute, getClient } from '@hcengineering/presentation'
|
||||||
|
import { getCurrentLocation } from '@hcengineering/ui'
|
||||||
|
|
||||||
import { type DocumentId } from './tiptap'
|
import { type DocumentId } from './tiptap'
|
||||||
|
|
||||||
|
function getWorkspace (): string {
|
||||||
|
return getCurrentLocation().path[1] ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
export function minioDocumentId (docId: Ref<Doc>, attr?: KeyedAttribute): DocumentId {
|
export function minioDocumentId (docId: Ref<Doc>, attr?: KeyedAttribute): DocumentId {
|
||||||
return attr !== undefined ? `minio://${docId}%${attr.key}` : `minio://${docId}`
|
const workspace = getWorkspace()
|
||||||
|
return attr !== undefined
|
||||||
|
? (`minio://${workspace}/${docId}%${attr.key}` as DocumentId)
|
||||||
|
: (`minio://${workspace}/${docId}` as DocumentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function platformDocumentId (docId: Ref<Doc>, attr: KeyedAttribute): DocumentId {
|
export function platformDocumentId (docId: Ref<Doc>, attr: KeyedAttribute): DocumentId {
|
||||||
return `platform://${attr.attr.attributeOf}/${docId}/${attr.key}`
|
const workspace = getWorkspace()
|
||||||
|
return `platform://${workspace}/${attr.attr.attributeOf}/${docId}/${attr.key}` as DocumentId
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mongodbDocumentId (docId: Ref<Doc>, attr: KeyedAttribute): DocumentId {
|
export function mongodbDocumentId (docId: Ref<Doc>, attr: KeyedAttribute): DocumentId {
|
||||||
|
const workspace = getWorkspace()
|
||||||
const domain = getClient().getHierarchy().getDomain(attr.attr.attributeOf)
|
const domain = getClient().getHierarchy().getDomain(attr.attr.attributeOf)
|
||||||
return `mongodb://${domain}/${docId}/${attr.key}`
|
return `mongodb://${workspace}/${domain}/${docId}/${attr.key}` as DocumentId
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ export function copyDocumentField (
|
|||||||
|
|
||||||
export function copyDocumentContent (
|
export function copyDocumentContent (
|
||||||
documentId: DocumentId,
|
documentId: DocumentId,
|
||||||
snapshotId: string,
|
snapshotId: DocumentId,
|
||||||
providerData: ProviderData,
|
providerData: ProviderData,
|
||||||
initialContentId?: DocumentId
|
initialContentId?: DocumentId
|
||||||
): void {
|
): void {
|
||||||
|
@ -143,7 +143,24 @@ export async function start (
|
|||||||
|
|
||||||
async onAuthenticate (data: onAuthenticatePayload): Promise<Context> {
|
async onAuthenticate (data: onAuthenticatePayload): Promise<Context> {
|
||||||
ctx.measure('authenticate', 1)
|
ctx.measure('authenticate', 1)
|
||||||
return buildContext(data, controller)
|
const context = buildContext(data, controller)
|
||||||
|
|
||||||
|
// verify document name
|
||||||
|
let documentName = data.documentName
|
||||||
|
if (documentName.includes('://')) {
|
||||||
|
documentName = documentName.split('://', 2)[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (documentName.includes('/')) {
|
||||||
|
const [workspace] = documentName.split('/', 2)
|
||||||
|
if (workspace !== context.workspaceId.name) {
|
||||||
|
throw new Error('documentName must include workspace')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('documentName must include workspace')
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
},
|
},
|
||||||
|
|
||||||
async onDestroy (data: onDestroyPayload): Promise<void> {
|
async onDestroy (data: onDestroyPayload): Promise<void> {
|
||||||
|
@ -22,6 +22,23 @@ import { Context } from '../context'
|
|||||||
|
|
||||||
import { StorageAdapter } from './adapter'
|
import { StorageAdapter } from './adapter'
|
||||||
|
|
||||||
|
interface MinioDocumentId {
|
||||||
|
workspace: string
|
||||||
|
minioDocumentId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDocumentId (documentId: string): MinioDocumentId {
|
||||||
|
const [workspace, minioDocumentId] = documentId.split('/')
|
||||||
|
return {
|
||||||
|
workspace: workspace ?? '',
|
||||||
|
minioDocumentId: minioDocumentId ?? ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidDocumentId (documentId: MinioDocumentId, context: Context): boolean {
|
||||||
|
return documentId.minioDocumentId !== '' && documentId.workspace === context.workspaceId.name
|
||||||
|
}
|
||||||
|
|
||||||
function maybePlatformDocumentId (documentId: string): boolean {
|
function maybePlatformDocumentId (documentId: string): boolean {
|
||||||
return !documentId.includes('%')
|
return !documentId.includes('%')
|
||||||
}
|
}
|
||||||
@ -35,10 +52,17 @@ export class MinioStorageAdapter implements StorageAdapter {
|
|||||||
async loadDocument (documentId: string, context: Context): Promise<YDoc | undefined> {
|
async loadDocument (documentId: string, context: Context): Promise<YDoc | undefined> {
|
||||||
const { workspaceId } = context
|
const { workspaceId } = context
|
||||||
|
|
||||||
|
const { workspace, minioDocumentId } = parseDocumentId(documentId)
|
||||||
|
|
||||||
|
if (!isValidDocumentId({ workspace, minioDocumentId }, context)) {
|
||||||
|
console.warn('malformed document id', documentId)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
return await this.ctx.with('load-document', {}, async (ctx) => {
|
return await this.ctx.with('load-document', {}, async (ctx) => {
|
||||||
const minioDocument = await ctx.with('query', {}, async () => {
|
const minioDocument = await ctx.with('query', {}, async () => {
|
||||||
try {
|
try {
|
||||||
const buffer = await this.minio.read(workspaceId, documentId)
|
const buffer = await this.minio.read(workspaceId, minioDocumentId)
|
||||||
return Buffer.concat(buffer)
|
return Buffer.concat(buffer)
|
||||||
} catch {
|
} catch {
|
||||||
return undefined
|
return undefined
|
||||||
@ -67,6 +91,13 @@ export class MinioStorageAdapter implements StorageAdapter {
|
|||||||
async saveDocument (documentId: string, document: YDoc, context: Context): Promise<void> {
|
async saveDocument (documentId: string, document: YDoc, context: Context): Promise<void> {
|
||||||
const { clientFactory, workspaceId } = context
|
const { clientFactory, workspaceId } = context
|
||||||
|
|
||||||
|
const { workspace, minioDocumentId } = parseDocumentId(documentId)
|
||||||
|
|
||||||
|
if (!isValidDocumentId({ workspace, minioDocumentId }, context)) {
|
||||||
|
console.warn('malformed document id', documentId)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
await this.ctx.with('save-document', {}, async (ctx) => {
|
await this.ctx.with('save-document', {}, async (ctx) => {
|
||||||
const buffer = await ctx.with('transform', {}, () => {
|
const buffer = await ctx.with('transform', {}, () => {
|
||||||
const updates = encodeStateAsUpdate(document)
|
const updates = encodeStateAsUpdate(document)
|
||||||
@ -75,13 +106,13 @@ export class MinioStorageAdapter implements StorageAdapter {
|
|||||||
|
|
||||||
await ctx.with('update', {}, async () => {
|
await ctx.with('update', {}, async () => {
|
||||||
const metadata = { 'content-type': 'application/ydoc' }
|
const metadata = { 'content-type': 'application/ydoc' }
|
||||||
await this.minio.put(workspaceId, documentId, buffer, buffer.length, metadata)
|
await this.minio.put(workspaceId, minioDocumentId, buffer, buffer.length, metadata)
|
||||||
})
|
})
|
||||||
|
|
||||||
// minio file is usually an attachment document
|
// minio file is usually an attachment document
|
||||||
// we need to touch an attachment from here to notify platform about changes
|
// we need to touch an attachment from here to notify platform about changes
|
||||||
|
|
||||||
if (!maybePlatformDocumentId(documentId)) {
|
if (!maybePlatformDocumentId(minioDocumentId)) {
|
||||||
// documentId is not a platform document id, we can skip platform notification
|
// documentId is not a platform document id, we can skip platform notification
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -92,7 +123,7 @@ export class MinioStorageAdapter implements StorageAdapter {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const current = await ctx.with('query', {}, async () => {
|
const current = await ctx.with('query', {}, async () => {
|
||||||
return await client.findOne(attachment.class.Attachment, { _id: documentId as Ref<Attachment> })
|
return await client.findOne(attachment.class.Attachment, { _id: minioDocumentId as Ref<Attachment> })
|
||||||
})
|
})
|
||||||
|
|
||||||
if (current !== undefined) {
|
if (current !== undefined) {
|
||||||
|
@ -23,22 +23,29 @@ import { Context } from '../context'
|
|||||||
import { StorageAdapter } from './adapter'
|
import { StorageAdapter } from './adapter'
|
||||||
|
|
||||||
interface MongodbDocumentId {
|
interface MongodbDocumentId {
|
||||||
|
workspace: string
|
||||||
objectDomain: string
|
objectDomain: string
|
||||||
objectId: string
|
objectId: string
|
||||||
objectAttr: string
|
objectAttr: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDocumentId (documentId: string): MongodbDocumentId {
|
function parseDocumentId (documentId: string): MongodbDocumentId {
|
||||||
const [objectDomain, objectId, objectAttr] = documentId.split('/')
|
const [workspace, objectDomain, objectId, objectAttr] = documentId.split('/')
|
||||||
return {
|
return {
|
||||||
|
workspace: workspace ?? '',
|
||||||
objectId: objectId ?? '',
|
objectId: objectId ?? '',
|
||||||
objectDomain: objectDomain ?? '',
|
objectDomain: objectDomain ?? '',
|
||||||
objectAttr: objectAttr ?? ''
|
objectAttr: objectAttr ?? ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidDocumentId (documentId: MongodbDocumentId): boolean {
|
function isValidDocumentId (documentId: MongodbDocumentId, context: Context): boolean {
|
||||||
return documentId.objectDomain !== '' && documentId.objectId !== '' && documentId.objectAttr !== ''
|
return (
|
||||||
|
documentId.objectDomain !== '' &&
|
||||||
|
documentId.objectId !== '' &&
|
||||||
|
documentId.objectAttr !== '' &&
|
||||||
|
documentId.workspace === context.workspaceId.name
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MongodbStorageAdapter implements StorageAdapter {
|
export class MongodbStorageAdapter implements StorageAdapter {
|
||||||
@ -49,17 +56,16 @@ export class MongodbStorageAdapter implements StorageAdapter {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async loadDocument (documentId: string, context: Context): Promise<YDoc | undefined> {
|
async loadDocument (documentId: string, context: Context): Promise<YDoc | undefined> {
|
||||||
const { workspaceId } = context
|
const { workspace, objectId, objectDomain, objectAttr } = parseDocumentId(documentId)
|
||||||
const { objectId, objectDomain, objectAttr } = parseDocumentId(documentId)
|
|
||||||
|
|
||||||
if (!isValidDocumentId({ objectId, objectDomain, objectAttr })) {
|
if (!isValidDocumentId({ workspace, objectId, objectDomain, objectAttr }, context)) {
|
||||||
console.warn('malformed document id', documentId)
|
console.warn('malformed document id', documentId)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.ctx.with('load-document', {}, async (ctx) => {
|
return await this.ctx.with('load-document', {}, async (ctx) => {
|
||||||
const doc = await ctx.with('query', {}, async () => {
|
const doc = await ctx.with('query', {}, async () => {
|
||||||
const db = this.mongodb.db(toWorkspaceString(workspaceId))
|
const db = this.mongodb.db(toWorkspaceString(context.workspaceId))
|
||||||
return await db.collection(objectDomain).findOne({ _id: objectId }, { projection: { [objectAttr]: 1 } })
|
return await db.collection(objectDomain).findOne({ _id: objectId }, { projection: { [objectAttr]: 1 } })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -22,22 +22,29 @@ import { Context } from '../context'
|
|||||||
import { StorageAdapter } from './adapter'
|
import { StorageAdapter } from './adapter'
|
||||||
|
|
||||||
interface PlatformDocumentId {
|
interface PlatformDocumentId {
|
||||||
|
workspace: string
|
||||||
objectClass: Ref<Class<Doc>>
|
objectClass: Ref<Class<Doc>>
|
||||||
objectId: Ref<Doc>
|
objectId: Ref<Doc>
|
||||||
objectAttr: string
|
objectAttr: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDocumentId (documentId: string): PlatformDocumentId {
|
function parseDocumentId (documentId: string): PlatformDocumentId {
|
||||||
const [objectClass, objectId, objectAttr] = documentId.split('/')
|
const [workspace, objectClass, objectId, objectAttr] = documentId.split('/')
|
||||||
return {
|
return {
|
||||||
|
workspace: workspace ?? '',
|
||||||
objectClass: (objectClass ?? '') as Ref<Class<Doc>>,
|
objectClass: (objectClass ?? '') as Ref<Class<Doc>>,
|
||||||
objectId: (objectId ?? '') as Ref<Doc>,
|
objectId: (objectId ?? '') as Ref<Doc>,
|
||||||
objectAttr: objectAttr ?? ''
|
objectAttr: objectAttr ?? ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidDocumentId (documentId: PlatformDocumentId): boolean {
|
function isValidDocumentId (documentId: PlatformDocumentId, context: Context): boolean {
|
||||||
return documentId.objectClass !== '' && documentId.objectId !== '' && documentId.objectAttr !== ''
|
return (
|
||||||
|
documentId.objectClass !== '' &&
|
||||||
|
documentId.objectId !== '' &&
|
||||||
|
documentId.objectAttr !== '' &&
|
||||||
|
documentId.workspace === context.workspaceId.name
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PlatformStorageAdapter implements StorageAdapter {
|
export class PlatformStorageAdapter implements StorageAdapter {
|
||||||
@ -48,9 +55,9 @@ export class PlatformStorageAdapter implements StorageAdapter {
|
|||||||
|
|
||||||
async loadDocument (documentId: string, context: Context): Promise<YDoc | undefined> {
|
async loadDocument (documentId: string, context: Context): Promise<YDoc | undefined> {
|
||||||
const { clientFactory } = context
|
const { clientFactory } = context
|
||||||
const { objectId, objectClass, objectAttr } = parseDocumentId(documentId)
|
const { workspace, objectId, objectClass, objectAttr } = parseDocumentId(documentId)
|
||||||
|
|
||||||
if (!isValidDocumentId({ objectId, objectClass, objectAttr })) {
|
if (!isValidDocumentId({ workspace, objectId, objectClass, objectAttr }, context)) {
|
||||||
console.warn('malformed document id', documentId)
|
console.warn('malformed document id', documentId)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
@ -77,9 +84,9 @@ export class PlatformStorageAdapter implements StorageAdapter {
|
|||||||
|
|
||||||
async saveDocument (documentId: string, document: YDoc, context: Context): Promise<void> {
|
async saveDocument (documentId: string, document: YDoc, context: Context): Promise<void> {
|
||||||
const { clientFactory } = context
|
const { clientFactory } = context
|
||||||
const { objectId, objectClass, objectAttr } = parseDocumentId(documentId)
|
const { workspace, objectId, objectClass, objectAttr } = parseDocumentId(documentId)
|
||||||
|
|
||||||
if (!isValidDocumentId({ objectId, objectClass, objectAttr })) {
|
if (!isValidDocumentId({ workspace, objectId, objectClass, objectAttr }, context)) {
|
||||||
console.warn('malformed document id', documentId)
|
console.warn('malformed document id', documentId)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user