Skip to content

Commit

Permalink
Merge pull request #100 from panoratech/nael/custom-fields
Browse files Browse the repository at this point in the history
feat: custom fields + remote data
  • Loading branch information
naelob authored Nov 26, 2023
2 parents 8d8af85 + 30d867a commit 1f13e4b
Show file tree
Hide file tree
Showing 61 changed files with 7,253 additions and 2,447 deletions.
39 changes: 20 additions & 19 deletions packages/api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -47,29 +47,13 @@ model crm_contacts {
crm_contact_email_addresses crm_contact_email_addresses[]
crm_users crm_users? @relation(fields: [id_crm_user], references: [id_crm_user], onDelete: NoAction, onUpdate: NoAction, map: "fk_23")
jobs jobs @relation(fields: [id_job], references: [id_job], onDelete: NoAction, onUpdate: NoAction, map: "job_id_crm_contact")
crm_contacts_phone_numbers crm_contacts_phone_numbers[]
crm_notes crm_notes[]
crm_phone_numbers crm_phone_numbers[]
@@index([id_job], map: "crm_contact_id_job")
@@index([id_crm_user], map: "fk_crm_contact_userid")
}

model crm_contacts_phone_numbers {
id_crm_contacts_phone_number String @id(map: "pk_crm_contacts_phone_numbers") @db.Uuid
phone_number String
phone_type String
owner_type String
created_at DateTime @db.Timestamp(6)
modified_at DateTime @db.Timestamp(6)
id_crm_company String @db.Uuid
id_crm_contact String @db.Uuid
crm_companies crm_companies @relation(fields: [id_crm_company], references: [id_crm_company], onDelete: NoAction, onUpdate: NoAction, map: "fk_17")
crm_contacts crm_contacts @relation(fields: [id_crm_contact], references: [id_crm_contact], onDelete: NoAction, onUpdate: NoAction, map: "fk_2")
@@index([id_crm_contact], map: "crm_contactid_crm_contact_phone_number")
@@index([id_crm_company], map: "fk_phone_number_companyid")
}

/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
model jobs {
id_job String @id(map: "pk_jobs") @db.Uuid
Expand Down Expand Up @@ -135,6 +119,7 @@ model users {
/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
model connections {
id_connection String @id(map: "pk_connections") @db.Uuid
status String
provider_slug String
account_url String?
token_type String
Expand All @@ -157,7 +142,6 @@ model linked_users {
id_linked_user String @id(map: "key_id_linked_users") @db.Uuid
linked_user_origin_id String
alias String
status String
id_project String @db.Uuid
connections connections[]
jobs jobs[]
Expand Down Expand Up @@ -213,9 +197,9 @@ model crm_companies {
jobs jobs @relation(fields: [id_job], references: [id_job], onDelete: NoAction, onUpdate: NoAction, map: "fk_13")
crm_users crm_users? @relation(fields: [id_crm_user], references: [id_crm_user], onDelete: NoAction, onUpdate: NoAction, map: "fk_24")
crm_contact_email_addresses crm_contact_email_addresses[]
crm_contacts_phone_numbers crm_contacts_phone_numbers[]
crm_engagements crm_engagements[]
crm_notes crm_notes[]
crm_phone_numbers crm_phone_numbers[]
crm_tasks crm_tasks[]
@@index([id_crm_user], map: "fk_crm_company_crm_userid")
Expand Down Expand Up @@ -367,3 +351,20 @@ model value {
@@index([id_attribute], map: "fk_value_attributeid")
@@index([id_entity], map: "fk_value_entityid")
}

/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
model crm_phone_numbers {
id_crm_contacts_phone_number String @id(map: "pk_crm_contacts_phone_numbers") @db.Uuid
phone_number String
phone_type String
owner_type String
created_at DateTime @db.Timestamp(6)
modified_at DateTime @db.Timestamp(6)
id_crm_company String? @db.Uuid
id_crm_contact String? @db.Uuid
crm_companies crm_companies? @relation(fields: [id_crm_company], references: [id_crm_company], onDelete: NoAction, onUpdate: NoAction, map: "fk_17")
crm_contacts crm_contacts? @relation(fields: [id_crm_contact], references: [id_crm_contact], onDelete: NoAction, onUpdate: NoAction, map: "fk_phonenumber_crm_contactid")
@@index([id_crm_contact], map: "crm_contactid_crm_contact_phone_number")
@@index([id_crm_company], map: "fk_phone_number_companyid")
}
3 changes: 1 addition & 2 deletions packages/api/src/@core/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { PassportModule } from '@nestjs/passport';
import { JwtModule, JwtService } from '@nestjs/jwt';
import { jwtConstants } from './utils/constants';
import { JwtStrategy } from './strategies/jwt.strategy';
import { ApiKeyStrategy } from './strategies/auth-header-api-key.strategy';
import { PrismaService } from '../prisma/prisma.service';
import { ConfigService } from '@nestjs/config';
import { LoggerService } from '../logger/logger.service';
import { LoggerService } from '@@core/logger/logger.service';

@Module({
providers: [
Expand Down
21 changes: 16 additions & 5 deletions packages/api/src/@core/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { CreateUserDto, LoginCredentials } from './dto/create-user.dto';
import { PrismaService } from '../prisma/prisma.service';
import * as bcrypt from 'bcrypt';
import * as crypto from 'crypto';
import { LoggerService } from '../logger/logger.service';
import { v4 as uuidv4 } from 'uuid';
import { LoggerService } from '@@core/logger/logger.service';

//TODO: Ensure the JWT is used for user session authentication and that it's short-lived.
@Injectable()
Expand All @@ -15,6 +16,16 @@ export class AuthService {
private logger: LoggerService,
) {}

async getUsers() {
const res = await this.prisma.users.findMany();
return res;
}

async getApiKeys() {
const res = await this.prisma.api_keys.findMany();
return res;
}

async register(user: CreateUserDto) {
try {
// Generate a salt and hash the password
Expand All @@ -23,7 +34,7 @@ export class AuthService {

const res = await this.prisma.users.create({
data: {
id_user: '1', //todo
id_user: uuidv4(),
email: user.email,
password_hash: hashedPassword,
first_name: user.first_name,
Expand Down Expand Up @@ -159,7 +170,7 @@ export class AuthService {
console.log('hey2');
const new_api_key = await this.prisma.api_keys.create({
data: {
id_api_key: '1', //TODO
id_api_key: uuidv4(),
api_key_hash: hashed_token,
id_project: projectId as string,
id_user: userId as string,
Expand Down Expand Up @@ -191,14 +202,14 @@ export class AuthService {
if (!saved_api_key) {
throw new UnauthorizedException('Failed to fetch API key from DB');
}
if (Number(decoded.projectId) !== Number(saved_api_key.id_project)) {
if (String(decoded.projectId) !== String(saved_api_key.id_project)) {
throw new UnauthorizedException(
'Failed to validate API key: projectId invalid.',
);
}

// Validate that the JWT payload matches the provided userId and projectId
if (Number(decoded.sub) !== Number(saved_api_key.id_user)) {
if (String(decoded.sub) !== String(saved_api_key.id_user)) {
throw new UnauthorizedException(
'Failed to validate API key: userId invalid.',
);
Expand Down
2 changes: 0 additions & 2 deletions packages/api/src/@core/auth/strategies/jwt.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtConstants } from '../utils/constants';
import { ConfigService } from '@nestjs/config';
import * as dotenv from 'dotenv';
dotenv.config();

Expand Down
15 changes: 11 additions & 4 deletions packages/api/src/@core/connections/connections.controller.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { Controller, Get, Query, Res } from '@nestjs/common';
import { Response } from 'express'; // Importing the Express Response type for type checking
import { Response } from 'express';
import { CrmConnectionsService } from './crm/services/crm-connection.service';
import { ProviderVertical, getProviderVertical } from '../utils/providers';
import { LoggerService } from '../logger/logger.service';
import { handleServiceError } from '../utils/errors';
import { ProviderVertical, getProviderVertical } from '@@core/utils/providers';
import { LoggerService } from '@@core/logger/logger.service';
import { handleServiceError } from '@@core/utils/errors';
import { PrismaService } from '@@core/prisma/prisma.service';

@Controller('connections')
export class ConnectionsController {
constructor(
private readonly crmConnectionsService: CrmConnectionsService,
private logger: LoggerService,
private prisma: PrismaService,
) {
this.logger.setContext(ConnectionsController.name);
}
Expand Down Expand Up @@ -59,4 +61,9 @@ export class ConnectionsController {
handleServiceError(error, this.logger);
}
}

@Get()
async getConnections() {
return await this.prisma.connections.findMany();
}
}
5 changes: 3 additions & 2 deletions packages/api/src/@core/connections/connections.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Module } from '@nestjs/common';
import { CrmConnectionModule } from './crm/crm-connection.module';
import { ConnectionsController } from './connections.controller';
import { LoggerService } from '../logger/logger.service';
import { LoggerService } from '@@core/logger/logger.service';
import { PrismaService } from '@@core/prisma/prisma.service';

@Module({
controllers: [ConnectionsController],
imports: [CrmConnectionModule],
providers: [LoggerService],
providers: [LoggerService, PrismaService],
})
export class ConnectionsModule {}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Module } from '@nestjs/common';
import { CrmConnectionsService } from './services/crm-connection.service';
import { PrismaService } from 'src/@core/prisma/prisma.service';
import { PrismaService } from '@@core/prisma/prisma.service';
import { FreshsalesConnectionService } from './services/freshsales/freshsales.service';
import { HubspotConnectionService } from './services/hubspot/hubspot.service';
import { PipedriveConnectionService } from './services/pipedrive/pipedrive.service';
import { ZendeskConnectionService } from './services/zendesk/zendesk.service';
import { ZohoConnectionService } from './services/zoho/zoho.service';
import { LoggerService } from 'src/@core/logger/logger.service';
import { LoggerService } from '@@core/logger/logger.service';

@Module({
providers: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/@core/prisma/prisma.service';
import { ZohoConnectionService } from './zoho/zoho.service';
import { NotFoundError } from 'src/@core/utils/errors';
import { NotFoundError } from '@@core/utils/errors';
import { HubspotConnectionService } from './hubspot/hubspot.service';
import { PipedriveConnectionService } from './pipedrive/pipedrive.service';
import { ZendeskConnectionService } from './zendesk/zendesk.service';
import { FreshsalesConnectionService } from './freshsales/freshsales.service';
import { LoggerService } from 'src/@core/logger/logger.service';
import { LoggerService } from '@@core/logger/logger.service';

@Injectable()
export class CrmConnectionsService {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/@core/prisma/prisma.service';
import { PrismaService } from '@@core/prisma/prisma.service';
import axios from 'axios';
import config from 'src/@core/utils/config';
import { Prisma } from '@prisma/client';
import config from '@@core/utils/config';
import { HubspotOAuthResponse } from '../../types';
import { LoggerService } from 'src/@core/logger/logger.service';
import { LoggerService } from '@@core/logger/logger.service';
import {
Action,
NotUniqueRecord,
handleServiceError,
} from 'src/@core/utils/errors';
} from '@@core/utils/errors';
import { v4 as uuidv4 } from 'uuid';
import { decrypt, encrypt } from '@@core/utils/crypto';

@Injectable()
export class HubspotConnectionService {
constructor(private prisma: PrismaService, private logger: LoggerService) {
this.logger.setContext(HubspotConnectionService.name);
}
async addLinkedUserAndProjectTest() {
// Adding a new organization
const newOrganization = {
id_organization: '1', //TODO
id_organization: uuidv4(),
name: 'New Organization',
stripe_customer_id: 'stripe-customer-123',
};
Expand All @@ -31,17 +31,17 @@ export class HubspotConnectionService {

// Example data for a new project
const newProject = {
id_project: '1',
id_project: uuidv4(),
name: 'New Project',
id_organization: '1',
id_organization: newOrganization.id_organization,
};
const data1 = await this.prisma.projects.create({
data: newProject,
});
this.logger.log('Added new project ' + data1);

const newLinkedUser = {
id_linked_user: '1',
id_linked_user: uuidv4(),
linked_user_origin_id: '12345',
alias: 'ACME COMPANY',
status: 'Active',
Expand All @@ -59,6 +59,7 @@ export class HubspotConnectionService {
code: string,
) {
try {
this.logger.log('linkeduserid is ' + linkedUserId);
const isNotUnique = await this.prisma.connections.findFirst({
where: {
id_linked_user: linkedUserId,
Expand All @@ -69,7 +70,20 @@ export class HubspotConnectionService {
`A connection already exists for userId ${linkedUserId} and the provider hubspot`,
);
//TMP STEP = first create a linked_user and a project id
await this.addLinkedUserAndProjectTest();
//await this.addLinkedUserAndProjectTest();

/*const newLinkedUser = {
id_linked_user: linkedUserId,
linked_user_origin_id: '12345',
alias: 'APPLE COMPANY',
status: 'Active',
id_project: projectId,
};
const data_ = await this.prisma.linked_users.create({
data: newLinkedUser,
});
this.logger.log('Added new linked_user ' + data_);*/

//reconstruct the redirect URI that was passed in the frontend it must be the same
const REDIRECT_URI = `${config.OAUTH_REDIRECT_BASE}/connections/oauth/callback`; //tocheck
const formData = new URLSearchParams({
Expand All @@ -95,14 +109,15 @@ export class HubspotConnectionService {
//TODO: encrypt the access token and refresh tokens
const db_res = await this.prisma.connections.create({
data: {
id_connection: '1', //TODO
id_connection: uuidv4(),
provider_slug: 'hubspot',
token_type: 'oauth',
access_token: data.access_token,
refresh_token: data.refresh_token,
access_token: encrypt(data.access_token),
refresh_token: encrypt(data.refresh_token),
expiration_timestamp: new Date(
new Date().getTime() + data.expires_in * 1000,
),
status: 'valid',
created_at: new Date(),
projects: {
connect: { id_project: projectId },
Expand All @@ -123,13 +138,12 @@ export class HubspotConnectionService {
async handleHubspotTokenRefresh(connectionId: string, refresh_token: string) {
try {
const REDIRECT_URI = `${config.OAUTH_REDIRECT_BASE}/connections/oauth/callback`; //tocheck

const formData = new URLSearchParams({
grant_type: 'refresh_token',
client_id: config.HUBSPOT_CLIENT_ID,
client_secret: config.HUBSPOT_CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
refresh_token: refresh_token,
refresh_token: decrypt(refresh_token),
});
const res = await axios.post(
'https://api.hubapi.com/oauth/v1/token',
Expand All @@ -146,8 +160,8 @@ export class HubspotConnectionService {
id_connection: connectionId,
},
data: {
access_token: data.access_token,
refresh_token: data.refresh_token,
access_token: encrypt(data.access_token),
refresh_token: encrypt(data.refresh_token),
expiration_timestamp: new Date(
new Date().getTime() + data.expires_in * 1000,
),
Expand Down
Loading

0 comments on commit 1f13e4b

Please sign in to comment.