mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-21 06:52:33 +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 attachment, { Attachment } from '@hcengineering/attachment'
|
||||
import { decode64, encode64 } from '../base64'
|
||||
import { WorkspaceLoginInfo } from '@hcengineering/account-client'
|
||||
|
||||
jest.mock('../config')
|
||||
|
||||
@ -41,7 +42,11 @@ describe('AttachmentHandler', () => {
|
||||
warn: 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 = {
|
||||
put: jest.fn(),
|
||||
read: jest.fn()
|
||||
@ -77,7 +82,13 @@ describe('AttachmentHandler', () => {
|
||||
let attachmentHandler: AttachmentHandler
|
||||
|
||||
beforeEach(() => {
|
||||
attachmentHandler = new AttachmentHandler(mockCtx, mockWorkspaceId, mockStorageAdapter, mockGmail, mockClient)
|
||||
attachmentHandler = new AttachmentHandler(
|
||||
mockCtx,
|
||||
mockWorkspaceLoginInfo,
|
||||
mockStorageAdapter,
|
||||
mockGmail,
|
||||
mockClient
|
||||
)
|
||||
})
|
||||
|
||||
describe('addAttachement', () => {
|
||||
|
@ -125,7 +125,14 @@ jest.mock('../config', () => ({
|
||||
}))
|
||||
|
||||
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', () => {
|
||||
|
@ -19,7 +19,13 @@ import { type StorageAdapter } from '@hcengineering/server-core'
|
||||
import setting from '@hcengineering/setting'
|
||||
import type { Credentials, OAuth2Client } from 'google-auth-library'
|
||||
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 config from './config'
|
||||
@ -94,19 +100,19 @@ export class GmailClient {
|
||||
private readonly gmail: gmail_v1.Resource$Users,
|
||||
private readonly user: User,
|
||||
client: Client,
|
||||
workspaceId: WorkspaceUuid,
|
||||
accountClient: AccountClient,
|
||||
wsInfo: WorkspaceLoginInfo,
|
||||
storageAdapter: StorageAdapter,
|
||||
private readonly workspace: WorkspaceClient,
|
||||
email: string,
|
||||
private socialId: SocialId
|
||||
) {
|
||||
this.email = email
|
||||
this.integrationToken = serviceToken(workspaceId)
|
||||
this.tokenStorage = new TokenStorage(this.ctx, workspaceId, this.integrationToken)
|
||||
this.integrationToken = serviceToken(wsInfo.workspace)
|
||||
this.tokenStorage = new TokenStorage(this.ctx, wsInfo.workspace, this.integrationToken)
|
||||
this.client = new TxOperations(client, this.socialId._id)
|
||||
this.account = this.user.userId
|
||||
this.attachmentHandler = new AttachmentHandler(ctx, workspaceId, storageAdapter, this.gmail, this.client)
|
||||
const accountClient = getAccountClient(config.AccountsURL, this.integrationToken)
|
||||
this.attachmentHandler = new AttachmentHandler(ctx, wsInfo, storageAdapter, this.gmail, this.client)
|
||||
const keyValueClient = getKvsClient(this.integrationToken)
|
||||
this.messageManager = createMessageManager(
|
||||
ctx,
|
||||
@ -164,13 +170,22 @@ export class GmailClient {
|
||||
}
|
||||
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(
|
||||
ctx,
|
||||
oAuth2Client,
|
||||
googleClient,
|
||||
user,
|
||||
client,
|
||||
workspaceId,
|
||||
accountClient,
|
||||
workspaceInfo,
|
||||
storageAdapter,
|
||||
workspace,
|
||||
email,
|
||||
|
@ -14,18 +14,19 @@
|
||||
//
|
||||
import { randomUUID } from 'crypto'
|
||||
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 { type Attachment as AttachedFile } from '@hcengineering/mail-common'
|
||||
import { gmail_v1 } from 'googleapis'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { WorkspaceLoginInfo } from '@hcengineering/account-client'
|
||||
|
||||
import { encode64 } from '../base64'
|
||||
import { addFooter } from '../utils'
|
||||
|
||||
export class AttachmentHandler {
|
||||
constructor (
|
||||
private readonly ctx: MeasureContext,
|
||||
private readonly workspaceId: WorkspaceUuid,
|
||||
private readonly wsInfo: WorkspaceLoginInfo,
|
||||
private readonly storageAdapter: StorageAdapter,
|
||||
private readonly gmail: gmail_v1.Resource$Users,
|
||||
private readonly client: TxOperations
|
||||
@ -36,22 +37,32 @@ export class AttachmentHandler {
|
||||
if (currentAttachemtns.findIndex((p) => p.name === file.name && p.lastModified === file.lastModified) !== -1) {
|
||||
return
|
||||
}
|
||||
const id = uuid()
|
||||
const data: AttachedData<Attachment> = {
|
||||
name: file.name,
|
||||
file: id as Ref<Blob>,
|
||||
type: file.data.toString('base64') ?? 'undefined',
|
||||
size: file.size ?? file.data.length,
|
||||
lastModified: file.lastModified ?? Date.now()
|
||||
}
|
||||
await this.storageAdapter.put(this.ctx, this.workspaceId as any, id, file.data, data.type, data.size) // TODO: FIXME
|
||||
const fileId = file.id ?? randomUUID()
|
||||
await this.storageAdapter.put(
|
||||
this.ctx,
|
||||
{
|
||||
uuid: this.wsInfo.workspace,
|
||||
url: this.wsInfo.workspaceUrl,
|
||||
dataId: this.wsInfo.workspaceDataId
|
||||
},
|
||||
fileId,
|
||||
file.data,
|
||||
file.contentType,
|
||||
file.size
|
||||
)
|
||||
await this.client.addCollection(
|
||||
attachment.class.Attachment,
|
||||
message.space,
|
||||
message._id,
|
||||
message._class,
|
||||
'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) {
|
||||
this.ctx.error('Add attachment error', { error: err.message })
|
||||
@ -153,16 +164,33 @@ export class AttachmentHandler {
|
||||
}
|
||||
|
||||
private async makeAttachmentPart (attachment: Attachment): Promise<string[]> {
|
||||
const buffer = await this.storageAdapter.read(this.ctx, this.workspaceId as any, attachment.file) // TODO: FIXME
|
||||
const data = Buffer.concat(buffer.map((b) => new Uint8Array(b))).toString('base64')
|
||||
const res: string[] = []
|
||||
res.push('--mail\n')
|
||||
res.push(`Content-Type: ${attachment.type}\n`)
|
||||
res.push('MIME-Version: 1.0\n')
|
||||
res.push('Content-Transfer-Encoding: base64\n')
|
||||
res.push(`Content-Disposition: attachment; filename="${attachment.name}"\n\n`)
|
||||
res.push(data)
|
||||
res.push('\n\n')
|
||||
return res
|
||||
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 res: string[] = []
|
||||
res.push('--mail\n')
|
||||
res.push(`Content-Type: ${attachment.type}\n`)
|
||||
res.push('MIME-Version: 1.0\n')
|
||||
res.push('Content-Transfer-Encoding: base64\n')
|
||||
res.push(`Content-Disposition: attachment; filename="${attachment.name}"\n\n`)
|
||||
res.push(data)
|
||||
res.push('\n\n')
|
||||
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