Skip to content

Commit

Permalink
Merge branch 'add-attion-crm' of https://github.com/mit-27/Panora int…
Browse files Browse the repository at this point in the history
…o mit-27-add-attion-crm
  • Loading branch information
naelob committed Mar 20, 2024
2 parents cedf587 + 9459865 commit 8637c30
Show file tree
Hide file tree
Showing 21 changed files with 577 additions and 23 deletions.
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ ZENDESK_SELL_CLIENT_SECRET=
# Freshsales
FRESHSALES_CLIENT_ID=
FRESHSALES_CLIENT_SECRET=
# Attio
ATTIO_CLIENT_ID=
ATTIO_CLIENT_SECRET=
# ================================================
# Ticketing
# ================================================
Expand All @@ -55,7 +58,8 @@ ZENDESK_TICKETING_CLIENT_SECRET=
# Must be set in the perspective of the end user browser

NEXT_PUBLIC_BACKEND_DOMAIN=http://localhost:3000 # https://api.panora.dev/
NEXT_PUBLIC_FRONTEND_DOMAIN=http://127.0.0.1:5173
NEXT_PUBLIC_FRONTEND_DOMAIN=http://localhost:81
NEXT_PUBLIC_ML_FRONTED_DOMAIN=http://localhost:81
NEXT_PUBLIC_POSTHOG_KEY=<ph_project_api_key>
NEXT_PUBLIC_POSTHOG_HOST=<ph_instance_address>
NEXT_PUBLIC_DISTRIBUTION="managed" #managed or self-host
Expand Down
Binary file added apps/client-ts/public/providers/crm/attio.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 7 additions & 2 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ services:
ENCRYPT_CRYPTO_SECRET_KEY: ${ENCRYPT_CRYPTO_SECRET_KEY}
HUBSPOT_CLIENT_ID: ${HUBSPOT_CLIENT_ID}
HUBSPOT_CLIENT_SECRET: ${HUBSPOT_CLIENT_SECRET}
ATTIO_CLIENT_ID: ${ATTIO_CLIENT_ID}
ATTIO_CLIENT_SECRET: ${ATTIO_CLIENT_SECRET}
ZOHOCRM_CLIENT_ID: ${ZOHOCRM_CLIENT_ID}
ZOHOCRM_CLIENT_SECRET: ${ZOHOCRM_CLIENT_SECRET}
PIPEDRIVE_CLIENT_ID: ${PIPEDRIVE_CLIENT_ID}
Expand Down Expand Up @@ -82,8 +84,8 @@ services:
dockerfile: ./apps/client-ts/Dockerfile.dev
context: ./
args:
VITE_BACKEND_DOMAIN: ${VITE_BACKEND_DOMAIN}
VITE_FRONTEND_DOMAIN: ${VITE_FRONTEND_DOMAIN}
VITE_BACKEND_DOMAIN: ${NEXT_PUBLIC_BACKEND_DOMAIN}
VITE_FRONTEND_DOMAIN: ${NEXT_PUBLIC_FRONTEND_DOMAIN}
environment:
NEXT_PUBLIC_STYTCH_SECRET: ${NEXT_PUBLIC_STYTCH_SECRET}
NEXT_PUBLIC_STYTCH_PROJECT_ID: ${NEXT_PUBLIC_STYTCH_PROJECT_ID}
Expand Down Expand Up @@ -111,6 +113,9 @@ services:
build:
dockerfile: ./apps/magic-link/Dockerfile.dev
context: ./
args:
VITE_BACKEND_DOMAIN: ${NEXT_PUBLIC_BACKEND_DOMAIN}
VITE_ML_FRONTEND_URL: ${NEXT_PUBLIC_ML_FRONTED_DOMAIN}
restart:
always
ports:
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.source.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ services:
ENCRYPT_CRYPTO_SECRET_KEY: ${ENCRYPT_CRYPTO_SECRET_KEY}
HUBSPOT_CLIENT_ID: ${HUBSPOT_CLIENT_ID}
HUBSPOT_CLIENT_SECRET: ${HUBSPOT_CLIENT_SECRET}
ATTIO_CLIENT_ID: ${ATTIO_CLIENT_ID}
ATTIO_CLIENT_SECRET: ${ATTIO_CLIENT_SECRET}
ZOHOCRM_CLIENT_ID: ${ZOHOCRM_CLIENT_ID}
ZOHOCRM_CLIENT_SECRET: ${ZOHOCRM_CLIENT_SECRET}
PIPEDRIVE_CLIENT_ID: ${PIPEDRIVE_CLIENT_ID}
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ services:
ENCRYPT_CRYPTO_SECRET_KEY: ${ENCRYPT_CRYPTO_SECRET_KEY}
HUBSPOT_CLIENT_ID: ${HUBSPOT_CLIENT_ID}
HUBSPOT_CLIENT_SECRET: ${HUBSPOT_CLIENT_SECRET}
ATTIO_CLIENT_ID: ${ATTIO_CLIENT_ID}
ATTIO_CLIENT_SECRET: ${ATTIO_CLIENT_SECRET}
ZOHOCRM_CLIENT_ID: ${ZOHOCRM_CLIENT_ID}
ZOHOCRM_CLIENT_SECRET: ${ZOHOCRM_CLIENT_SECRET}
PIPEDRIVE_CLIENT_ID: ${PIPEDRIVE_CLIENT_ID}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { HubspotConnectionService } from './services/hubspot/hubspot.service';
import { ZohoConnectionService } from './services/zoho/zoho.service';
import { ZendeskConnectionService } from './services/zendesk/zendesk.service';
import { PipedriveConnectionService } from './services/pipedrive/pipedrive.service';
import { AttioConnectionService } from './services/attio/attio.service';

@Module({
imports: [WebhookModule],
Expand All @@ -26,10 +27,11 @@ import { PipedriveConnectionService } from './services/pipedrive/pipedrive.servi
// PROVIDERS SERVICES
FreshsalesConnectionService,
HubspotConnectionService,
AttioConnectionService,
ZohoConnectionService,
ZendeskConnectionService,
PipedriveConnectionService,
],
exports: [CrmConnectionsService],
})
export class CrmConnectionModule {}
export class CrmConnectionModule { }
117 changes: 117 additions & 0 deletions packages/api/src/@core/connections/crm/services/attio/attio.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { Injectable } from "@nestjs/common";
import {
AttioOAuthResponse,
CallbackParams,
ICrmConnectionService,
RefreshParams,
} from "../../types";
import { PrismaService } from '@@core/prisma/prisma.service';
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';
import { Action, handleServiceError } from '@@core/utils/errors';
import { EnvironmentService } from '@@core/environment/environment.service';
import { EncryptionService } from '@@core/encryption/encryption.service';
import { ServiceConnectionRegistry } from '../registry.service';
import { LoggerService } from '@@core/logger/logger.service';


@Injectable()
export class AttioConnectionService implements ICrmConnectionService {
constructor(
private prisma: PrismaService,
private logger: LoggerService,
private env: EnvironmentService,
private cryptoService: EncryptionService,
private registry: ServiceConnectionRegistry
) {
this.logger.setContext(AttioConnectionService.name);
this.registry.registerService("attio", this);
}

async handleCallback(opts: CallbackParams) {
try {
console.log("Linked User iD : <MMMMKIIT")
const { linkedUserId, projectId, code } = opts;
this.logger.log(
'linkeduserid is ' + linkedUserId + ' inside callback attio',
);
const isNotUnique = await this.prisma.connections.findFirst({
where: {
id_linked_user: linkedUserId,
provider_slug: 'attio',
},
});
if (isNotUnique) return;
//reconstruct the redirect URI that was passed in the frontend it must be the same
const REDIRECT_URI = `${this.env.getOAuthRredirectBaseUrl()}/connections/oauth/callback`;
const formData = new URLSearchParams({
grant_type: 'authorization_code',
client_id: this.env.getAttioAuth().CLIENT_ID,
client_secret: this.env.getAttioAuth().CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
code: code,
});

const res = await axios.post(
'https://app.attio.com/oauth/token',
formData.toString(),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
},
},
);

const data: AttioOAuthResponse = res.data;

// Saving the token of customer inside db
let db_res;
const connection_token = uuidv4();

if (isNotUnique) {
// Update existing connection
db_res = await this.prisma.connections.update({
where: {
id_connection: isNotUnique.id_connection,
},
data: {
access_token: this.cryptoService.encrypt(data.access_token),
status: 'valid',
created_at: new Date(),
},
});
} else {
// Create new connection
db_res = await this.prisma.connections.create({
data: {
id_connection: uuidv4(),
connection_token: connection_token,
provider_slug: 'attio',
token_type: 'oauth',
access_token: this.cryptoService.encrypt(data.access_token),
status: 'valid',
created_at: new Date(),
projects: {
connect: { id_project: projectId },
},
linked_users: {
connect: { id_linked_user: linkedUserId },
},
},
});
}
this.logger.log('Successfully added tokens inside DB ' + db_res);
return db_res;


} catch (error) {
handleServiceError(error, this.logger, 'attio', Action.oauthCallback);

}
}

// It is not required for Attio as it does not provide refresh_token
async handleTokenRefresh(opts: RefreshParams) {
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export class CrmConnectionsService {
}

const serviceName = providerName.toLowerCase();

const service = this.serviceRegistry.getService(serviceName);

if (!service) {
Expand Down
5 changes: 5 additions & 0 deletions packages/api/src/@core/connections/crm/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export interface HubspotOAuthResponse {
access_token: string;
expires_in: number;
}

export interface AttioOAuthResponse {
access_token: string,
token_type: string;
}
export interface ZohoOAuthResponse {
access_token: string;
refresh_token: string;
Expand Down
10 changes: 9 additions & 1 deletion packages/api/src/@core/environment/environment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type RateLimit = {

@Injectable()
export class EnvironmentService {
constructor(private configService: ConfigService) {}
constructor(private configService: ConfigService) { }

getEnvMode(): string {
return this.configService.get<string>('ENV');
Expand Down Expand Up @@ -46,6 +46,14 @@ export class EnvironmentService {
CLIENT_SECRET: this.configService.get<string>('HUBSPOT_CLIENT_SECRET'),
};
}

getAttioAuth(): OAuth {
return {
CLIENT_ID: this.configService.get<string>('ATTIO_CLIENT_ID'),
CLIENT_SECRET: this.configService.get<string>('ATTIO_CLIENT_SECRET'),
}
}

getZohoSecret(): OAuth {
return {
CLIENT_ID: this.configService.get<string>('ZOHO_CLIENT_ID'),
Expand Down
4 changes: 4 additions & 0 deletions packages/api/src/@core/utils/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type StandardObject = TargetObject;
export const domains = {
CRM: {
hubspot: 'https://api.hubapi.com',
attio: 'https://developers.attio.com',
zoho: 'https://www.zohoapis.eu/crm/v3',
zendesk: 'https://api.getbase.com/v2',
freshsales: '',
Expand All @@ -43,6 +44,7 @@ export const customPropertiesUrls = {
hubspot: `${domains['CRM']['hubspot']}/properties/v1/contacts/properties`,
zoho: `${domains['CRM']['zoho']}/settings/fields?module=Contact`,
zendesk: `${domains['CRM']['zendesk']}/contact/custom_fields`,
attio: `${domains['CRM']['attio']}/docs/standard-objects-people`,
freshsales: `${domains['CRM']['freshsales']}`, //TODO
pipedrive: `${domains['CRM']['pipedrive']}/v1/personFields`,
},
Expand All @@ -67,6 +69,7 @@ export enum CrmProviders {
HUBSPOT = 'hubspot',
PIPEDRIVE = 'pipedrive',
FRESHSALES = 'freshsales',
ATTIO = 'attio',
}

export enum AccountingProviders {
Expand All @@ -85,6 +88,7 @@ export const CRM_PROVIDERS = [
'hubspot',
'pipedrive',
'freshsales',
'attio',
];

export const HRIS_PROVIDERS = [''];
Expand Down
1 change: 1 addition & 0 deletions packages/api/src/crm/@utils/@types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export * from '../../contact/services/zendesk/types';
export * from '../../contact/services/hubspot/types';
export * from '../../contact/services/zoho/types';
export * from '../../contact/services/pipedrive/types';
export * from '../../contact/services/attio/types'

/* user */
export * from '../../user/services/freshsales/types';
Expand Down
4 changes: 3 additions & 1 deletion packages/api/src/crm/contact/contact.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ContactController } from './contact.controller';
import { PrismaService } from '@@core/prisma/prisma.service';
import { FreshsalesService } from './services/freshsales';
import { ZendeskService } from './services/zendesk';
import { AttioService } from './services/attio'
import { ZohoService } from './services/zoho';
import { PipedriveService } from './services/pipedrive';
import { HubspotService } from './services/hubspot';
Expand Down Expand Up @@ -33,11 +34,12 @@ import { ServiceRegistry } from './services/registry.service';
ServiceRegistry,
/* PROVIDERS SERVICES */
FreshsalesService,
AttioService,
ZendeskService,
ZohoService,
PipedriveService,
HubspotService,
],
exports: [SyncContactsService],
})
export class ContactModule {}
export class ContactModule { }
Loading

0 comments on commit 8637c30

Please sign in to comment.