3242 all message recipients should be stored (#3320)
* saveMessageRecipients * update * workspaceMemberId is working * merge * get direction of the message * fix * improve code * modify GmailMessage type
This commit is contained in:
@ -1,9 +1,12 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import axios, { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { simpleParser } from 'mailparser';
|
||||
import { simpleParser, AddressObject } from 'mailparser';
|
||||
|
||||
import { GmailMessage } from 'src/workspace/messaging/types/gmailMessage';
|
||||
import {
|
||||
GmailMessage,
|
||||
Recipient,
|
||||
} from 'src/workspace/messaging/types/gmailMessage';
|
||||
import { MessageOrThreadQuery } from 'src/workspace/messaging/types/messageOrThreadQuery';
|
||||
import { GmailMessageParsedResponse } from 'src/workspace/messaging/types/gmailMessageParsedResponse';
|
||||
import { GmailThreadParsedResponse } from 'src/workspace/messaging/types/gmailThreadParsedResponse';
|
||||
@ -208,16 +211,25 @@ export class FetchBatchMessagesService {
|
||||
attachments,
|
||||
} = parsed;
|
||||
|
||||
if (!from) throw new Error('From value is missing');
|
||||
if (!to) throw new Error('To value is missing');
|
||||
|
||||
const recipients = [
|
||||
...this.formatAddressObjectAsRecipients(from, 'from'),
|
||||
...this.formatAddressObjectAsRecipients(to, 'to'),
|
||||
...this.formatAddressObjectAsRecipients(cc, 'cc'),
|
||||
...this.formatAddressObjectAsRecipients(bcc, 'bcc'),
|
||||
];
|
||||
|
||||
const messageFromGmail: GmailMessage = {
|
||||
externalId: id,
|
||||
headerMessageId: messageId || '',
|
||||
subject: subject || '',
|
||||
messageThreadId: threadId,
|
||||
internalDate,
|
||||
from,
|
||||
to,
|
||||
cc,
|
||||
bcc,
|
||||
fromHandle: from.value[0].address || '',
|
||||
fromDisplayName: from.value[0].name || '',
|
||||
recipients,
|
||||
text: text || '',
|
||||
html: html || '',
|
||||
attachments,
|
||||
@ -237,6 +249,36 @@ export class FetchBatchMessagesService {
|
||||
return filteredResponse;
|
||||
}
|
||||
|
||||
formatAddressObjectAsArray(
|
||||
addressObject: AddressObject | AddressObject[],
|
||||
): AddressObject[] {
|
||||
return Array.isArray(addressObject) ? addressObject : [addressObject];
|
||||
}
|
||||
|
||||
formatAddressObjectAsRecipients(
|
||||
addressObject: AddressObject | AddressObject[] | undefined,
|
||||
role: 'from' | 'to' | 'cc' | 'bcc',
|
||||
): Recipient[] {
|
||||
if (!addressObject) return [];
|
||||
const addressObjects = this.formatAddressObjectAsArray(addressObject);
|
||||
|
||||
const recipients = addressObjects.map((addressObject) => {
|
||||
const emailAdresses = addressObject.value;
|
||||
|
||||
return emailAdresses.map((emailAddress) => {
|
||||
const { name, address } = emailAddress;
|
||||
|
||||
return {
|
||||
role,
|
||||
handle: address || '',
|
||||
displayName: name || '',
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return recipients.flat();
|
||||
}
|
||||
|
||||
async formatBatchResponsesAsGmailMessages(
|
||||
batchResponses: AxiosResponse<any, any>[],
|
||||
): Promise<GmailMessage[]> {
|
||||
|
||||
@ -2,12 +2,15 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { gmail_v1 } from 'googleapis';
|
||||
import { v4 } from 'uuid';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { DataSource, EntityManager } from 'typeorm';
|
||||
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { DataSourceService } from 'src/metadata/data-source/data-source.service';
|
||||
import { FetchBatchMessagesService } from 'src/workspace/messaging/services/fetch-batch-messages.service';
|
||||
import { GmailMessage } from 'src/workspace/messaging/types/gmailMessage';
|
||||
import {
|
||||
GmailMessage,
|
||||
Recipient,
|
||||
} from 'src/workspace/messaging/types/gmailMessage';
|
||||
import { MessageOrThreadQuery } from 'src/workspace/messaging/types/messageOrThreadQuery';
|
||||
import { DataSourceEntity } from 'src/metadata/data-source/data-source.entity';
|
||||
import { GmailClientProvider } from 'src/workspace/messaging/providers/gmail/gmail-client.provider';
|
||||
@ -34,7 +37,6 @@ export class FetchWorkspaceMessagesService {
|
||||
|
||||
const accessToken = connectedAccount.accessToken;
|
||||
const refreshToken = connectedAccount.refreshToken;
|
||||
const workspaceMemberId = connectedAccount.workspaceMemberId;
|
||||
|
||||
if (!refreshToken) {
|
||||
throw new Error('No refresh token found');
|
||||
@ -106,7 +108,7 @@ export class FetchWorkspaceMessagesService {
|
||||
messagesResponse,
|
||||
dataSourceMetadata,
|
||||
workspaceDataSource,
|
||||
workspaceMemberId,
|
||||
connectedAccount,
|
||||
);
|
||||
}
|
||||
|
||||
@ -137,7 +139,7 @@ export class FetchWorkspaceMessagesService {
|
||||
messages: GmailMessage[],
|
||||
dataSourceMetadata: DataSourceEntity,
|
||||
workspaceDataSource: DataSource,
|
||||
workspaceMemberId: string,
|
||||
connectedAccount,
|
||||
) {
|
||||
for (const message of messages) {
|
||||
const {
|
||||
@ -146,7 +148,9 @@ export class FetchWorkspaceMessagesService {
|
||||
subject,
|
||||
messageThreadId,
|
||||
internalDate,
|
||||
from,
|
||||
fromHandle,
|
||||
fromDisplayName,
|
||||
recipients,
|
||||
text,
|
||||
} = message;
|
||||
|
||||
@ -158,16 +162,26 @@ export class FetchWorkspaceMessagesService {
|
||||
);
|
||||
|
||||
const messageId = v4();
|
||||
const handle = from?.value[0]?.address;
|
||||
const displayName = from?.value[0]?.name;
|
||||
|
||||
const person = await workspaceDataSource?.query(
|
||||
`SELECT * FROM ${dataSourceMetadata.schema}."person" WHERE "email" = $1`,
|
||||
[handle],
|
||||
[fromHandle],
|
||||
);
|
||||
|
||||
const personId = person[0]?.id;
|
||||
|
||||
const workspaceMember = await workspaceDataSource?.query(
|
||||
`SELECT "workspaceMember"."id" FROM ${dataSourceMetadata.schema}."workspaceMember"
|
||||
JOIN ${dataSourceMetadata.schema}."connectedAccount" ON ${dataSourceMetadata.schema}."workspaceMember"."id" = ${dataSourceMetadata.schema}."connectedAccount"."accountOwnerId"
|
||||
WHERE ${dataSourceMetadata.schema}."connectedAccount"."handle" = $1`,
|
||||
[fromHandle],
|
||||
);
|
||||
|
||||
const workspaceMemberId = workspaceMember[0]?.id;
|
||||
|
||||
const messageDirection =
|
||||
connectedAccount.handle === fromHandle ? 'outgoing' : 'incoming';
|
||||
|
||||
await workspaceDataSource?.transaction(async (manager) => {
|
||||
await manager.query(
|
||||
`INSERT INTO ${dataSourceMetadata.schema}."message" ("id", "externalId", "headerMessageId", "subject", "date", "messageThreadId", "direction", "body") VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
||||
@ -178,19 +192,72 @@ export class FetchWorkspaceMessagesService {
|
||||
subject,
|
||||
date,
|
||||
messageThread[0]?.id,
|
||||
'incoming',
|
||||
messageDirection,
|
||||
text,
|
||||
],
|
||||
);
|
||||
|
||||
await manager.query(
|
||||
`INSERT INTO ${dataSourceMetadata.schema}."messageRecipient" ("messageId", "role", "handle", "displayName", "personId", "workspaceMemberId") VALUES ($1, $2, $3, $4, $5, $6)`,
|
||||
[messageId, 'from', handle, displayName, personId, workspaceMemberId],
|
||||
[
|
||||
messageId,
|
||||
'from',
|
||||
fromHandle,
|
||||
fromDisplayName,
|
||||
personId,
|
||||
workspaceMemberId,
|
||||
],
|
||||
);
|
||||
|
||||
await this.saveMessageRecipients(
|
||||
recipients,
|
||||
dataSourceMetadata,
|
||||
messageId,
|
||||
manager,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async saveMessageRecipients(
|
||||
recipients: Recipient[],
|
||||
dataSourceMetadata: DataSourceEntity,
|
||||
messageId: string,
|
||||
manager: EntityManager,
|
||||
): Promise<void> {
|
||||
if (!recipients) return;
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const recipientPerson = await manager.query(
|
||||
`SELECT * FROM ${dataSourceMetadata.schema}."person" WHERE "email" = $1`,
|
||||
[recipient.handle],
|
||||
);
|
||||
|
||||
const recipientPersonId = recipientPerson[0]?.id;
|
||||
|
||||
const workspaceMember = await manager.query(
|
||||
`SELECT "workspaceMember"."id" FROM ${dataSourceMetadata.schema}."workspaceMember"
|
||||
JOIN ${dataSourceMetadata.schema}."connectedAccount" ON ${dataSourceMetadata.schema}."workspaceMember"."id" = ${dataSourceMetadata.schema}."connectedAccount"."accountOwnerId"
|
||||
WHERE ${dataSourceMetadata.schema}."connectedAccount"."handle" = $1`,
|
||||
[recipient.handle],
|
||||
);
|
||||
|
||||
const recipientWorkspaceMemberId = workspaceMember[0]?.id;
|
||||
|
||||
await manager.query(
|
||||
`INSERT INTO ${dataSourceMetadata.schema}."messageRecipient" ("messageId", "role", "handle", "displayName", "personId", "workspaceMemberId") VALUES ($1, $2, $3, $4, $5, $6)`,
|
||||
[
|
||||
messageId,
|
||||
recipient.role,
|
||||
recipient.handle,
|
||||
recipient.displayName,
|
||||
recipientPersonId,
|
||||
recipientWorkspaceMemberId,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async getAllSavedMessagesIdsAndMessageThreadsIdsForConnectedAccount(
|
||||
dataSourceMetadata: DataSourceEntity,
|
||||
workspaceDataSource: DataSource,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AddressObject, Attachment } from 'mailparser';
|
||||
import { Attachment } from 'mailparser';
|
||||
|
||||
export type GmailMessage = {
|
||||
externalId: string;
|
||||
@ -6,11 +6,16 @@ export type GmailMessage = {
|
||||
subject: string;
|
||||
messageThreadId: string;
|
||||
internalDate: string;
|
||||
from: AddressObject | undefined;
|
||||
to: AddressObject | AddressObject[] | undefined;
|
||||
cc: AddressObject | AddressObject[] | undefined;
|
||||
bcc: AddressObject | AddressObject[] | undefined;
|
||||
fromHandle: string;
|
||||
fromDisplayName: string;
|
||||
recipients: Recipient[];
|
||||
text: string;
|
||||
html: string;
|
||||
attachments: Attachment[];
|
||||
};
|
||||
|
||||
export type Recipient = {
|
||||
role: 'from' | 'to' | 'cc' | 'bcc';
|
||||
handle: string;
|
||||
displayName: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user