Add workspacePreQueryHook module (#3879)

* rebase

* reorganise messaging folders

* fix

* fix after review

* fix yarn lock
This commit is contained in:
Weiko
2024-02-13 18:23:29 +01:00
committed by GitHub
parent 36b69a8625
commit 458e8c839f
63 changed files with 494 additions and 70 deletions

View File

@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { CreateCompanyService } from 'src/workspace/messaging/services/create-company/create-company.service';
@Module({
imports: [],
providers: [CreateCompanyService],
exports: [CreateCompanyService],
})
export class CreateCompanyModule {}

View File

@ -0,0 +1,106 @@
import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm';
import axios, { AxiosInstance } from 'axios';
import { v4 } from 'uuid';
import { DataSourceEntity } from 'src/metadata/data-source/data-source.entity';
import { capitalize } from 'src/utils/capitalize';
@Injectable()
export class CreateCompanyService {
private readonly httpService: AxiosInstance;
constructor() {
this.httpService = axios.create({
baseURL: 'https://companies.twenty.com',
});
}
async createCompanies(
domainNames: string[],
dataSourceMetadata: DataSourceEntity,
manager: EntityManager,
): Promise<{
[domainName: string]: string;
}> {
const uniqueDomainNames = [...new Set(domainNames)];
const existingCompanies = await manager.query(
`SELECT id, "domainName" FROM ${dataSourceMetadata.schema}.company WHERE "domainName" = ANY($1)`,
[uniqueDomainNames],
);
const companiesObject = existingCompanies.reduce(
(
acc: {
[domainName: string]: string;
},
company: {
domainName: string;
id: string;
},
) => ({
...acc,
[company.domainName]: company.id,
}),
{},
);
const filteredDomainNames = uniqueDomainNames.filter(
(domainName) =>
!existingCompanies.some(
(company: { domainName: string }) =>
company.domainName === domainName,
),
);
for (const domainName of filteredDomainNames) {
companiesObject[domainName] = await this.createCompany(
domainName,
dataSourceMetadata,
manager,
);
}
return companiesObject;
}
async createCompany(
domainName: string,
dataSourceMetadata: DataSourceEntity,
manager: EntityManager,
): Promise<string> {
const companyId = v4();
const { name, city } = await this.getCompanyInfoFromDomainName(domainName);
await manager.query(
`INSERT INTO ${dataSourceMetadata.schema}.company (id, name, "domainName", address)
VALUES ($1, $2, $3, $4)`,
[companyId, name, domainName, city],
);
return companyId;
}
async getCompanyInfoFromDomainName(domainName: string): Promise<{
name: string;
city: string;
}> {
try {
const response = await this.httpService.get(`/${domainName}`);
const data = response.data;
return {
name: data.name,
city: data.city,
};
} catch (e) {
return {
name: capitalize(domainName.split('.')[0]),
city: '',
};
}
}
}

View File

@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { CreateContactService } from 'src/workspace/messaging/services/create-contact/create-contact.service';
@Module({
imports: [],
providers: [CreateContactService],
exports: [CreateContactService],
})
export class CreateContactModule {}

View File

@ -0,0 +1,88 @@
import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm';
import { v4 } from 'uuid';
import { DataSourceEntity } from 'src/metadata/data-source/data-source.entity';
import { capitalize } from 'src/utils/capitalize';
type ContactToCreate = {
handle: string;
displayName: string;
companyId: string;
};
type FormattedContactToCreate = {
id: string;
handle: string;
firstName: string;
lastName: string;
companyId: string;
};
@Injectable()
export class CreateContactService {
constructor() {}
formatContacts(
contactsToCreate: ContactToCreate[],
): FormattedContactToCreate[] {
return contactsToCreate.map((contact) => {
const { handle, displayName, companyId } = contact;
const contactFirstName = displayName.split(' ')[0];
const contactLastName = displayName.split(' ')[1];
const contactFullNameFromHandle = handle.split('@')[0];
const contactFirstNameFromHandle =
contactFullNameFromHandle.split('.')[0];
const contactLastNameFromHandle = contactFullNameFromHandle.split('.')[1];
const id = v4();
return {
id,
handle,
firstName: capitalize(
contactFirstName || contactFirstNameFromHandle || '',
),
lastName: capitalize(
contactLastName || contactLastNameFromHandle || '',
),
companyId,
};
});
}
async createContacts(
contactsToCreate: ContactToCreate[],
dataSourceMetadata: DataSourceEntity,
manager: EntityManager,
): Promise<void> {
if (contactsToCreate.length === 0) return;
const formattedContacts = this.formatContacts(contactsToCreate);
const valuesString = formattedContacts
.map(
(_, index) =>
`($${index * 5 + 1}, $${index * 5 + 2}, $${index * 5 + 3}, $${
index * 5 + 4
}, $${index * 5 + 5})`,
)
.join(', ');
await manager.query(
`INSERT INTO ${dataSourceMetadata.schema}.person (id, email, "nameFirstName", "nameLastName", "companyId") VALUES ${valuesString}`,
formattedContacts
.map((contact) => [
contact.id,
contact.handle,
contact.firstName,
contact.lastName,
contact.companyId,
])
.flat(),
);
}
}

View File

@ -1,18 +1,18 @@
import { Inject, Injectable, Logger } from '@nestjs/common';
import { FetchMessagesByBatchesService } from 'src/workspace/messaging/services/fetch-messages-by-batches.service';
import { GmailClientProvider } from 'src/workspace/messaging/providers/gmail/gmail-client.provider';
import { GmailClientProvider } from 'src/workspace/messaging/services/providers/gmail/gmail-client.provider';
import { MessageQueue } from 'src/integrations/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/integrations/message-queue/services/message-queue.service';
import {
GmailFullSyncJobData,
GmailFullSyncJob,
} from 'src/workspace/messaging/jobs/gmail-full-sync.job';
import { ConnectedAccountService } from 'src/workspace/messaging/connected-account/connected-account.service';
import { MessageChannelService } from 'src/workspace/messaging/message-channel/message-channel.service';
import { MessageChannelMessageAssociationService } from 'src/workspace/messaging/message-channel-message-association/message-channel-message-association.service';
import { ConnectedAccountService } from 'src/workspace/messaging/repositories/connected-account/connected-account.service';
import { MessageChannelService } from 'src/workspace/messaging/repositories/message-channel/message-channel.service';
import { MessageChannelMessageAssociationService } from 'src/workspace/messaging/repositories/message-channel-message-association/message-channel-message-association.service';
import { WorkspaceDataSourceService } from 'src/workspace/workspace-datasource/workspace-datasource.service';
import { MessageService } from 'src/workspace/messaging/message/message.service';
import { MessageService } from 'src/workspace/messaging/repositories/message/message.service';
import { createQueriesFromMessageIds } from 'src/workspace/messaging/utils/create-queries-from-message-ids.util';
@Injectable()

View File

@ -3,17 +3,17 @@ import { Inject, Injectable, Logger } from '@nestjs/common';
import { gmail_v1 } from 'googleapis';
import { FetchMessagesByBatchesService } from 'src/workspace/messaging/services/fetch-messages-by-batches.service';
import { GmailClientProvider } from 'src/workspace/messaging/providers/gmail/gmail-client.provider';
import { GmailClientProvider } from 'src/workspace/messaging/services/providers/gmail/gmail-client.provider';
import { MessageQueueService } from 'src/integrations/message-queue/services/message-queue.service';
import { MessageQueue } from 'src/integrations/message-queue/message-queue.constants';
import {
GmailFullSyncJob,
GmailFullSyncJobData,
} from 'src/workspace/messaging/jobs/gmail-full-sync.job';
import { ConnectedAccountService } from 'src/workspace/messaging/connected-account/connected-account.service';
import { ConnectedAccountService } from 'src/workspace/messaging/repositories/connected-account/connected-account.service';
import { WorkspaceDataSourceService } from 'src/workspace/workspace-datasource/workspace-datasource.service';
import { MessageChannelService } from 'src/workspace/messaging/message-channel/message-channel.service';
import { MessageService } from 'src/workspace/messaging/message/message.service';
import { MessageChannelService } from 'src/workspace/messaging/repositories/message-channel/message-channel.service';
import { MessageService } from 'src/workspace/messaging/repositories/message/message.service';
import { createQueriesFromMessageIds } from 'src/workspace/messaging/utils/create-queries-from-message-ids.util';
@Injectable()

View File

@ -3,7 +3,7 @@ import { Injectable } from '@nestjs/common';
import axios from 'axios';
import { EnvironmentService } from 'src/integrations/environment/environment.service';
import { ConnectedAccountService } from 'src/workspace/messaging/connected-account/connected-account.service';
import { ConnectedAccountService } from 'src/workspace/messaging/repositories/connected-account/connected-account.service';
@Injectable()
export class GmailRefreshAccessTokenService {

View File

@ -0,0 +1,39 @@
import { Injectable } from '@nestjs/common';
import { OAuth2Client } from 'google-auth-library';
import { gmail_v1, google } from 'googleapis';
import { EnvironmentService } from 'src/integrations/environment/environment.service';
@Injectable()
export class GmailClientProvider {
constructor(private readonly environmentService: EnvironmentService) {}
public async getGmailClient(refreshToken: string): Promise<gmail_v1.Gmail> {
const oAuth2Client = await this.getOAuth2Client(refreshToken);
const gmailClient = google.gmail({
version: 'v1',
auth: oAuth2Client,
});
return gmailClient;
}
private async getOAuth2Client(refreshToken: string): Promise<OAuth2Client> {
const gmailClientId = this.environmentService.getAuthGoogleClientId();
const gmailClientSecret =
this.environmentService.getAuthGoogleClientSecret();
const oAuth2Client = new google.auth.OAuth2(
gmailClientId,
gmailClientSecret,
);
oAuth2Client.setCredentials({
refresh_token: refreshToken,
});
return oAuth2Client;
}
}

View File

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { EnvironmentModule } from 'src/integrations/environment/environment.module';
import { GmailClientProvider } from 'src/workspace/messaging/services/providers/gmail/gmail-client.provider';
@Module({
imports: [EnvironmentModule],
providers: [GmailClientProvider],
exports: [GmailClientProvider],
})
export class MessagingProvidersModule {}