mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-23 16:25:48 +00:00
UBERF-10631: Fix attachments in old gmail integration (#8971)
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / uitest-workspaces (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / uitest-workspaces (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
parent
ede948676f
commit
845ec007bf
@ -15,6 +15,7 @@ import { AttachmentHandler } from '../message/attachments'
|
|||||||
import type { Attachment as AttachedFile } from '@hcengineering/mail-common'
|
import type { Attachment as AttachedFile } from '@hcengineering/mail-common'
|
||||||
import attachment, { Attachment } from '@hcengineering/attachment'
|
import attachment, { Attachment } from '@hcengineering/attachment'
|
||||||
import { decode64, encode64 } from '../base64'
|
import { decode64, encode64 } from '../base64'
|
||||||
|
import { WorkspaceLoginInfo } from '@hcengineering/account-client'
|
||||||
|
|
||||||
jest.mock('../config')
|
jest.mock('../config')
|
||||||
|
|
||||||
@ -41,7 +42,11 @@ describe('AttachmentHandler', () => {
|
|||||||
warn: jest.fn(),
|
warn: jest.fn(),
|
||||||
end: jest.fn()
|
end: jest.fn()
|
||||||
}
|
}
|
||||||
const mockWorkspaceId = 'test-workspace' as WorkspaceUuid
|
const mockWorkspaceLoginInfo: WorkspaceLoginInfo = {
|
||||||
|
endpoint: 'wss://test-endpoint.com',
|
||||||
|
workspace: 'test-workspace' as WorkspaceUuid,
|
||||||
|
token: 'test-token'
|
||||||
|
} as any
|
||||||
const mockStorageAdapter = {
|
const mockStorageAdapter = {
|
||||||
put: jest.fn(),
|
put: jest.fn(),
|
||||||
read: jest.fn()
|
read: jest.fn()
|
||||||
@ -77,7 +82,13 @@ describe('AttachmentHandler', () => {
|
|||||||
let attachmentHandler: AttachmentHandler
|
let attachmentHandler: AttachmentHandler
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
attachmentHandler = new AttachmentHandler(mockCtx, mockWorkspaceId, mockStorageAdapter, mockGmail, mockClient)
|
attachmentHandler = new AttachmentHandler(
|
||||||
|
mockCtx,
|
||||||
|
mockWorkspaceLoginInfo,
|
||||||
|
mockStorageAdapter,
|
||||||
|
mockGmail,
|
||||||
|
mockClient
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('addAttachement', () => {
|
describe('addAttachement', () => {
|
||||||
|
@ -125,7 +125,14 @@ jest.mock('../config', () => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
jest.mock('@hcengineering/account-client', () => ({
|
jest.mock('@hcengineering/account-client', () => ({
|
||||||
getClient: jest.fn()
|
getClient: jest.fn().mockImplementation(() => ({
|
||||||
|
getLoginInfoByToken: jest.fn().mockResolvedValue({
|
||||||
|
endpoint: 'wss://test-endpoint.com',
|
||||||
|
workspace: 'mockWorkspaceId',
|
||||||
|
token: 'test-token'
|
||||||
|
})
|
||||||
|
})),
|
||||||
|
isWorkspaceLoginInfo: jest.fn().mockImplementation(() => true)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
describe('GmailClient', () => {
|
describe('GmailClient', () => {
|
||||||
|
@ -19,7 +19,13 @@ import { type StorageAdapter } from '@hcengineering/server-core'
|
|||||||
import setting from '@hcengineering/setting'
|
import setting from '@hcengineering/setting'
|
||||||
import type { Credentials, OAuth2Client } from 'google-auth-library'
|
import type { Credentials, OAuth2Client } from 'google-auth-library'
|
||||||
import { gmail_v1, google } from 'googleapis'
|
import { gmail_v1, google } from 'googleapis'
|
||||||
import { getClient as getAccountClient, Integration } from '@hcengineering/account-client'
|
import {
|
||||||
|
getClient as getAccountClient,
|
||||||
|
Integration,
|
||||||
|
WorkspaceLoginInfo,
|
||||||
|
isWorkspaceLoginInfo,
|
||||||
|
AccountClient
|
||||||
|
} from '@hcengineering/account-client'
|
||||||
|
|
||||||
import { encode64 } from './base64'
|
import { encode64 } from './base64'
|
||||||
import config from './config'
|
import config from './config'
|
||||||
@ -94,19 +100,19 @@ export class GmailClient {
|
|||||||
private readonly gmail: gmail_v1.Resource$Users,
|
private readonly gmail: gmail_v1.Resource$Users,
|
||||||
private readonly user: User,
|
private readonly user: User,
|
||||||
client: Client,
|
client: Client,
|
||||||
workspaceId: WorkspaceUuid,
|
accountClient: AccountClient,
|
||||||
|
wsInfo: WorkspaceLoginInfo,
|
||||||
storageAdapter: StorageAdapter,
|
storageAdapter: StorageAdapter,
|
||||||
private readonly workspace: WorkspaceClient,
|
private readonly workspace: WorkspaceClient,
|
||||||
email: string,
|
email: string,
|
||||||
private socialId: SocialId
|
private socialId: SocialId
|
||||||
) {
|
) {
|
||||||
this.email = email
|
this.email = email
|
||||||
this.integrationToken = serviceToken(workspaceId)
|
this.integrationToken = serviceToken(wsInfo.workspace)
|
||||||
this.tokenStorage = new TokenStorage(this.ctx, workspaceId, this.integrationToken)
|
this.tokenStorage = new TokenStorage(this.ctx, wsInfo.workspace, this.integrationToken)
|
||||||
this.client = new TxOperations(client, this.socialId._id)
|
this.client = new TxOperations(client, this.socialId._id)
|
||||||
this.account = this.user.userId
|
this.account = this.user.userId
|
||||||
this.attachmentHandler = new AttachmentHandler(ctx, workspaceId, storageAdapter, this.gmail, this.client)
|
this.attachmentHandler = new AttachmentHandler(ctx, wsInfo, storageAdapter, this.gmail, this.client)
|
||||||
const accountClient = getAccountClient(config.AccountsURL, this.integrationToken)
|
|
||||||
const keyValueClient = getKvsClient(this.integrationToken)
|
const keyValueClient = getKvsClient(this.integrationToken)
|
||||||
this.messageManager = createMessageManager(
|
this.messageManager = createMessageManager(
|
||||||
ctx,
|
ctx,
|
||||||
@ -164,13 +170,22 @@ export class GmailClient {
|
|||||||
}
|
}
|
||||||
user.socialId = socialId
|
user.socialId = socialId
|
||||||
|
|
||||||
|
const integrationToken = serviceToken(workspaceId)
|
||||||
|
const accountClient = getAccountClient(config.AccountsURL, integrationToken)
|
||||||
|
const workspaceInfo = await accountClient.getLoginInfoByToken()
|
||||||
|
if (!isWorkspaceLoginInfo(workspaceInfo)) {
|
||||||
|
ctx.error('Unable to get workspace info', { workspaceId, email })
|
||||||
|
throw new Error('Unable to get workspace info')
|
||||||
|
}
|
||||||
|
|
||||||
const gmailClient = new GmailClient(
|
const gmailClient = new GmailClient(
|
||||||
ctx,
|
ctx,
|
||||||
oAuth2Client,
|
oAuth2Client,
|
||||||
googleClient,
|
googleClient,
|
||||||
user,
|
user,
|
||||||
client,
|
client,
|
||||||
workspaceId,
|
accountClient,
|
||||||
|
workspaceInfo,
|
||||||
storageAdapter,
|
storageAdapter,
|
||||||
workspace,
|
workspace,
|
||||||
email,
|
email,
|
||||||
|
@ -14,18 +14,19 @@
|
|||||||
//
|
//
|
||||||
import { randomUUID } from 'crypto'
|
import { randomUUID } from 'crypto'
|
||||||
import attachment, { Attachment } from '@hcengineering/attachment'
|
import attachment, { Attachment } from '@hcengineering/attachment'
|
||||||
import { AttachedData, Blob, MeasureContext, Ref, TxOperations, WorkspaceUuid } from '@hcengineering/core'
|
import { Blob, MeasureContext, Ref, TxOperations } from '@hcengineering/core'
|
||||||
import { StorageAdapter } from '@hcengineering/server-core'
|
import { StorageAdapter } from '@hcengineering/server-core'
|
||||||
import { type Attachment as AttachedFile } from '@hcengineering/mail-common'
|
import { type Attachment as AttachedFile } from '@hcengineering/mail-common'
|
||||||
import { gmail_v1 } from 'googleapis'
|
import { gmail_v1 } from 'googleapis'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { WorkspaceLoginInfo } from '@hcengineering/account-client'
|
||||||
|
|
||||||
import { encode64 } from '../base64'
|
import { encode64 } from '../base64'
|
||||||
import { addFooter } from '../utils'
|
import { addFooter } from '../utils'
|
||||||
|
|
||||||
export class AttachmentHandler {
|
export class AttachmentHandler {
|
||||||
constructor (
|
constructor (
|
||||||
private readonly ctx: MeasureContext,
|
private readonly ctx: MeasureContext,
|
||||||
private readonly workspaceId: WorkspaceUuid,
|
private readonly wsInfo: WorkspaceLoginInfo,
|
||||||
private readonly storageAdapter: StorageAdapter,
|
private readonly storageAdapter: StorageAdapter,
|
||||||
private readonly gmail: gmail_v1.Resource$Users,
|
private readonly gmail: gmail_v1.Resource$Users,
|
||||||
private readonly client: TxOperations
|
private readonly client: TxOperations
|
||||||
@ -36,22 +37,32 @@ export class AttachmentHandler {
|
|||||||
if (currentAttachemtns.findIndex((p) => p.name === file.name && p.lastModified === file.lastModified) !== -1) {
|
if (currentAttachemtns.findIndex((p) => p.name === file.name && p.lastModified === file.lastModified) !== -1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const id = uuid()
|
const fileId = file.id ?? randomUUID()
|
||||||
const data: AttachedData<Attachment> = {
|
await this.storageAdapter.put(
|
||||||
name: file.name,
|
this.ctx,
|
||||||
file: id as Ref<Blob>,
|
{
|
||||||
type: file.data.toString('base64') ?? 'undefined',
|
uuid: this.wsInfo.workspace,
|
||||||
size: file.size ?? file.data.length,
|
url: this.wsInfo.workspaceUrl,
|
||||||
lastModified: file.lastModified ?? Date.now()
|
dataId: this.wsInfo.workspaceDataId
|
||||||
}
|
},
|
||||||
await this.storageAdapter.put(this.ctx, this.workspaceId as any, id, file.data, data.type, data.size) // TODO: FIXME
|
fileId,
|
||||||
|
file.data,
|
||||||
|
file.contentType,
|
||||||
|
file.size
|
||||||
|
)
|
||||||
await this.client.addCollection(
|
await this.client.addCollection(
|
||||||
attachment.class.Attachment,
|
attachment.class.Attachment,
|
||||||
message.space,
|
message.space,
|
||||||
message._id,
|
message._id,
|
||||||
message._class,
|
message._class,
|
||||||
'attachments',
|
'attachments',
|
||||||
data
|
{
|
||||||
|
name: file.name,
|
||||||
|
file: fileId as Ref<Blob>,
|
||||||
|
type: file.data.toString('base64') ?? 'undefined',
|
||||||
|
size: file.size ?? file.data.length,
|
||||||
|
lastModified: file.lastModified ?? Date.now()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this.ctx.error('Add attachment error', { error: err.message })
|
this.ctx.error('Add attachment error', { error: err.message })
|
||||||
@ -153,7 +164,16 @@ export class AttachmentHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async makeAttachmentPart (attachment: Attachment): Promise<string[]> {
|
private async makeAttachmentPart (attachment: Attachment): Promise<string[]> {
|
||||||
const buffer = await this.storageAdapter.read(this.ctx, this.workspaceId as any, attachment.file) // TODO: FIXME
|
try {
|
||||||
|
const buffer = await this.storageAdapter.read(
|
||||||
|
this.ctx,
|
||||||
|
{
|
||||||
|
uuid: this.wsInfo.workspace,
|
||||||
|
url: this.wsInfo.workspaceUrl,
|
||||||
|
dataId: this.wsInfo.workspaceDataId
|
||||||
|
},
|
||||||
|
attachment.file
|
||||||
|
)
|
||||||
const data = Buffer.concat(buffer.map((b) => new Uint8Array(b))).toString('base64')
|
const data = Buffer.concat(buffer.map((b) => new Uint8Array(b))).toString('base64')
|
||||||
const res: string[] = []
|
const res: string[] = []
|
||||||
res.push('--mail\n')
|
res.push('--mail\n')
|
||||||
@ -164,5 +184,13 @@ export class AttachmentHandler {
|
|||||||
res.push(data)
|
res.push(data)
|
||||||
res.push('\n\n')
|
res.push('\n\n')
|
||||||
return res
|
return res
|
||||||
|
} catch (err: any) {
|
||||||
|
this.ctx.error('Failed to make attachment part', {
|
||||||
|
error: err.message,
|
||||||
|
file: attachment.file,
|
||||||
|
name: attachment.name
|
||||||
|
})
|
||||||
|
return []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user