UBERF-4905 Change collaborator client payload (#4392)

Signed-off-by: Alexander Onnikov <alexander.onnikov@xored.com>
This commit is contained in:
Alexander Onnikov 2024-01-19 22:27:52 +07:00 committed by GitHub
parent b4d898be5b
commit c0c17993cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 86 additions and 38 deletions

View File

@ -13,7 +13,8 @@
// limitations under the License.
//
import { Class, Doc, Markup, Ref, concatLink } from '@hcengineering/core'
import { Class, Doc, Hierarchy, Markup, Ref, concatLink } from '@hcengineering/core'
import { minioDocumentId, mongodbDocumentId } from './utils'
/**
* @public
@ -26,18 +27,32 @@ export interface CollaboratorClient {
/**
* @public
*/
export function getClient (token: string, collaboratorUrl: string): CollaboratorClient {
return new CollaboratorClientImpl(token, collaboratorUrl)
export function getClient (hierarchy: Hierarchy, token: string, collaboratorUrl: string): CollaboratorClient {
return new CollaboratorClientImpl(hierarchy, token, collaboratorUrl)
}
class CollaboratorClientImpl implements CollaboratorClient {
constructor (
private readonly hierarchy: Hierarchy,
private readonly token: string,
private readonly collaboratorUrl: string
) {}
initialContentId (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string): string {
const domain = this.hierarchy.getDomain(classId)
return mongodbDocumentId(domain, docId, attribute)
}
async get (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string): Promise<Markup> {
const url = concatLink(this.collaboratorUrl, `/api/content/${classId}/${docId}/${attribute}`)
const documentId = encodeURIComponent(minioDocumentId(docId, attribute))
const initialContentId = encodeURIComponent(this.initialContentId(classId, docId, attribute))
attribute = encodeURIComponent(attribute)
const url = concatLink(
this.collaboratorUrl,
`/api/content/${documentId}/${attribute}?initialContentId=${initialContentId}`
)
const res = await fetch(url, {
method: 'GET',
headers: {
@ -50,7 +65,15 @@ class CollaboratorClientImpl implements CollaboratorClient {
}
async update (classId: Ref<Class<Doc>>, docId: Ref<Doc>, attribute: string, value: Markup): Promise<void> {
const url = concatLink(this.collaboratorUrl, `/api/content/${classId}/${docId}/${attribute}`)
const documentId = encodeURIComponent(minioDocumentId(docId, attribute))
const initialContentId = encodeURIComponent(this.initialContentId(classId, docId, attribute))
attribute = encodeURIComponent(attribute)
const url = concatLink(
this.collaboratorUrl,
`/api/content/${documentId}/${attribute}?initialContentId=${initialContentId}`
)
await fetch(url, {
method: 'PUT',
headers: {

View File

@ -14,3 +14,4 @@
//
export { type CollaboratorClient, getClient } from './client'
export * from './utils'

View File

@ -0,0 +1,24 @@
//
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import { Doc, Domain, Ref } from '@hcengineering/core'
export function minioDocumentId (docId: Ref<Doc>, attribute?: string): string {
return attribute !== undefined ? `minio://${docId}%${attribute}` : `minio://${docId}`
}
export function mongodbDocumentId (domain: Domain, docId: Ref<Doc>, attribute: string): string {
return `mongodb://${domain}/${docId}/${attribute}`
}

View File

@ -13,20 +13,22 @@
// limitations under the License.
//
import { type CollaboratorClient, getClient } from '@hcengineering/collaborator-client'
import { type CollaboratorClient, getClient as getCollaborator } from '@hcengineering/collaborator-client'
import type { Class, Doc, Markup, Ref } from '@hcengineering/core'
import { getMetadata } from '@hcengineering/platform'
import { getClient } from '.'
import presentation from './plugin'
/**
* @public
*/
export function getCollaboratorClient (): CollaboratorClient {
const hierarchy = getClient().getHierarchy()
const token = getMetadata(presentation.metadata.Token) ?? ''
const collaboratorURL = getMetadata(presentation.metadata.CollaboratorUrl) ?? ''
return getClient(token, collaboratorURL)
return getCollaborator(hierarchy, token, collaboratorURL)
}
/**

View File

@ -153,18 +153,18 @@ export async function start (
const restCtx = ctx.newChild('REST', {})
const getContext = (token: Token, documentId: string): Context => {
const getContext = (token: Token, initialContentId?: string): Context => {
return {
connectionId: generateId(),
workspaceId: token.workspace,
clientFactory: getClientFactory(token, controller),
initialContentId: documentId,
initialContentId: initialContentId ?? '',
targetContentId: ''
}
}
// eslint-disable-next-line @typescript-eslint/no-misused-promises
app.get('/api/content/:classId/:docId/:attribute', async (req, res) => {
app.get('/api/content/:documentId/:field', async (req, res) => {
console.log('handle request', req.method, req.url)
const authHeader = req.headers.authorization
@ -176,22 +176,21 @@ export async function start (
const token = authHeader.split(' ')[1]
const decodedToken = decodeToken(token)
const docId = req.params.docId
const attribute = req.params.attribute
const documentId = req.params.documentId
const field = req.params.field
const initialContentId = req.query.initialContentId as string
if (docId === undefined || docId === '') {
res.status(400).send({ err: "'docId' is missing" })
if (documentId === undefined || documentId === '') {
res.status(400).send({ err: "'documentId' is missing" })
return
}
if (attribute === undefined || attribute === '') {
res.status(400).send({ err: "'attribute' is missing" })
if (field === undefined || field === '') {
res.status(400).send({ err: "'field' is missing" })
return
}
const documentId = `minio://${docId}%${attribute}`
const context = getContext(decodedToken, documentId)
const context = getContext(decodedToken, initialContentId)
await restCtx.with(`${req.method} /content`, {}, async (ctx) => {
const connection = await ctx.with('connect', {}, async () => {
@ -202,7 +201,7 @@ export async function start (
const html = await ctx.with('transform', {}, async () => {
let content = ''
await connection.transact((document) => {
content = transformer.fromYdoc(document, attribute)
content = transformer.fromYdoc(document, field)
})
return content
})
@ -221,7 +220,7 @@ export async function start (
})
// eslint-disable-next-line @typescript-eslint/no-misused-promises
app.put('/api/content/:classId/:docId/:attribute', async (req, res) => {
app.put('/api/content/:documentId/:field', async (req, res) => {
console.log('handle request', req.method, req.url)
const authHeader = req.headers.authorization
@ -233,27 +232,26 @@ export async function start (
const token = authHeader.split(' ')[1]
const decodedToken = decodeToken(token)
const docId = req.params.docId
const attribute = req.params.attribute
if (docId === undefined || docId === '') {
res.status(400).send({ err: "'docId' is missing" })
return
}
if (attribute === undefined || attribute === '') {
res.status(400).send({ err: "'attribute' is missing" })
return
}
const documentId = `minio://${docId}%${attribute}`
const documentId = req.params.documentId
const field = req.params.field
const initialContentId = req.query.initialContentId as string
const data = req.body.html ?? '<p></p>'
const context = getContext(decodedToken, documentId)
if (documentId === undefined || documentId === '') {
res.status(400).send({ err: "'documentId' is missing" })
return
}
if (field === undefined || field === '') {
res.status(400).send({ err: "'field' is missing" })
return
}
const context = getContext(decodedToken, initialContentId)
await restCtx.with(`${req.method} /content`, {}, async (ctx) => {
const update = await ctx.with('transform', {}, () => {
const ydoc = transformer.toYdoc(data, attribute)
const ydoc = transformer.toYdoc(data, field)
return encodeStateAsUpdate(ydoc)
})
@ -264,7 +262,7 @@ export async function start (
try {
await ctx.with('update', {}, async () => {
await connection.transact((document) => {
const fragment = document.getXmlFragment(attribute)
const fragment = document.getXmlFragment(field)
document.transact((tr) => {
fragment.delete(0, fragment.length)
applyUpdate(document, update)