From 9f3606424e14554c0dd900c2b3ce625bc06c4078 Mon Sep 17 00:00:00 2001 From: Alexander Onnikov Date: Mon, 14 Jul 2025 12:30:35 +0700 Subject: [PATCH] UBERF-12153 Update communication blob metadata (#9539) Signed-off-by: Alexander Onnikov --- packages/api-client/src/rest/rest.ts | 29 +++++++++++++++++++++++++++ packages/api-client/src/rest/types.ts | 17 +++++++++++++--- pods/media/src/client.ts | 29 ++++++++++++++++++++++++++- pods/media/src/handler.ts | 5 ++++- pods/server/src/rpc.ts | 9 +++++++++ 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/packages/api-client/src/rest/rest.ts b/packages/api-client/src/rest/rest.ts index 075fa1c8dc..48a0061130 100644 --- a/packages/api-client/src/rest/rest.ts +++ b/packages/api-client/src/rest/rest.ts @@ -20,11 +20,15 @@ import { concatLink, type Doc, type DocumentQuery, + type DomainParams, + type DomainRequestOptions, + type DomainResult, type FindOptions, type FindResult, Hierarchy, MeasureMetricsContext, ModelDb, + OperationDomain, PersonId, PersonUuid, type Ref, @@ -301,6 +305,31 @@ export class RestClientImpl implements RestClient { return result } + async domainRequest( + domain: OperationDomain, + params: DomainParams, + options?: DomainRequestOptions + ): Promise> { + const requestUrl = concatLink(this.endpoint, `/api/v1/request/${domain}/${this.workspace}`) + + await this.checkRate() + return await withRetry(async () => { + const response = await fetch(requestUrl, { + method: 'POST', + headers: this.jsonHeaders(), + keepalive: true, + body: JSON.stringify(params) + }) + if (!response.ok) { + await this.checkRateLimits(response) + throw new PlatformError(unknownError(response.statusText)) + } + this.updateRateLimit(response) + const value = await extractJson(response) + return { domain, value } + }, isRLE) + } + async ensurePerson ( socialType: SocialIdType, socialValue: string, diff --git a/packages/api-client/src/rest/types.ts b/packages/api-client/src/rest/types.ts index cb3efaf950..d878fcccce 100644 --- a/packages/api-client/src/rest/types.ts +++ b/packages/api-client/src/rest/types.ts @@ -14,18 +14,22 @@ // import { - PersonId, - PersonUuid, - SocialIdType, type Account, type Class, type Doc, type DocumentQuery, + type DomainParams, + type DomainRequestOptions, + type DomainResult, type FindOptions, type FulltextStorage, type Hierarchy, type ModelDb, + type OperationDomain, + type PersonId, + type PersonUuid, type Ref, + type SocialIdType, type Storage, type WithLookup } from '@hcengineering/core' @@ -40,6 +44,13 @@ export interface RestClient extends Storage, FulltextStorage { ) => Promise | undefined> getModel: () => Promise<{ hierarchy: Hierarchy, model: ModelDb }> + + domainRequest: ( + domain: OperationDomain, + params: DomainParams, + options?: DomainRequestOptions + ) => Promise> + ensurePerson: ( socialType: SocialIdType, socialValue: string, diff --git a/pods/media/src/client.ts b/pods/media/src/client.ts index 4df356949a..f81684d9cf 100644 --- a/pods/media/src/client.ts +++ b/pods/media/src/client.ts @@ -44,6 +44,7 @@ import core, { import { type RestClient, createRestClient } from '@hcengineering/api-client' import { getTransactorEndpoint } from '@hcengineering/server-client' import { generateToken } from '@hcengineering/server-token' +import { MessageEventType } from '@hcengineering/communication-sdk-types' import { BlobSourceType, type VideoTranscodeResult } from './types' @@ -121,6 +122,32 @@ export class WorkspaceClient { } } } + + async updateCommMetadata (ctx: MeasureContext, result: VideoTranscodeResult, metadata: BlobMetadata): Promise { + if (result.source.source !== BlobSourceType.Message) { + return + } + + const txOps = new TxOperations(this.client, core.account.System) + await txOps.domainRequest('communication' as OperationDomain, { + event: { + type: MessageEventType.BlobPatch, + cardId: result.source.cardId, + messageId: result.source.messageId, + operations: [ + { + opcode: 'update', + blobs: [ + { + blobId: result.blobId, + metadata + } + ] + } + ] + } + }) + } } function toHttpUrl (url: string): string { @@ -139,7 +166,7 @@ class RestClientAdapter implements Client { params: DomainParams, options?: DomainRequestOptions ): Promise> { - throw new Error('Domain request operation not supported') + return await this.client.domainRequest(domain, params, options) } async findAll( diff --git a/pods/media/src/handler.ts b/pods/media/src/handler.ts index 2c7be6a88b..d3a29ccad3 100644 --- a/pods/media/src/handler.ts +++ b/pods/media/src/handler.ts @@ -129,8 +129,11 @@ export async function handleTranscodeResult ( } } + const client = await WorkspaceClient.create(workspaceUuid) + if (msg.source !== undefined && msg.source.source === BlobSourceType.Doc) { - const client = await WorkspaceClient.create(workspaceUuid) await client.updateBlobMetadata(ctx, msg, metadata) + } else if (msg.source !== undefined && msg.source.source === BlobSourceType.Message) { + await client.updateCommMetadata(ctx, msg, metadata) } } diff --git a/pods/server/src/rpc.ts b/pods/server/src/rpc.ts index 6cb79779ef..4cd59d6de8 100644 --- a/pods/server/src/rpc.ts +++ b/pods/server/src/rpc.ts @@ -345,6 +345,15 @@ export function registerRPC (app: Express, sessions: SessionManager, ctx: Measur }) }) + app.post('/api/v1/request/:domain/:workspaceId', (req, res) => { + void withSession(req, res, async (ctx, session) => { + const domain = req.params.domain as OperationDomain + const params = retrieveJson(req) + const { result } = await session.domainRequestRaw(ctx, domain, params) + await sendJson(req, res, result.value) + }) + }) + app.post('/api/v1/ensure-person/:workspaceId', (req, res) => { void withSession(req, res, async (ctx, session, rateLimit, token) => { const { socialType, socialValue, firstName, lastName } = (await retrieveJson(req)) ?? {}