From f69c793de03dfe7e42f7aee71f0a26669244b6a2 Mon Sep 17 00:00:00 2001 From: nael Date: Wed, 12 Jun 2024 11:40:49 +0200 Subject: [PATCH 1/3] :white_check_mark: Testing zendesk realtime webhook --- docker-compose.dev.yml | 32 +++--- .../src/ticketing/@webhook/handler.module.ts | 6 +- .../src/ticketing/@webhook/zendesk/handler.ts | 97 ++++++++++++++++++- .../ticketing/account/services/front/index.ts | 1 + .../account/services/zendesk/index.ts | 10 +- .../ticketing/account/sync/sync.service.ts | 49 +++++++++- .../api/src/ticketing/account/types/index.ts | 1 + .../ticketing/contact/services/front/index.ts | 1 - .../contact/services/gorgias/index.ts | 1 - .../contact/services/zendesk/index.ts | 8 +- .../ticketing/contact/sync/sync.service.ts | 52 ++++++++-- .../api/src/ticketing/contact/types/index.ts | 2 +- .../ticketing/ticket/services/front/index.ts | 1 + .../ticketing/ticket/services/github/index.ts | 1 + .../ticketing/ticket/services/gitlab/index.ts | 1 + .../ticket/services/gorgias/index.ts | 1 + .../ticket/services/hubspot/index.ts | 1 + .../ticketing/ticket/services/jira/index.ts | 3 +- .../ticket/services/zendesk/index.ts | 11 ++- .../src/ticketing/ticket/sync/sync.service.ts | 48 ++++++++- .../api/src/ticketing/ticket/types/index.ts | 1 + .../ticketing/user/services/front/index.ts | 1 + .../ticketing/user/services/gitlab/index.ts | 1 + .../ticketing/user/services/gorgias/index.ts | 1 + .../src/ticketing/user/services/jira/index.ts | 1 + .../ticketing/user/services/zendesk/index.ts | 7 +- .../src/ticketing/user/sync/sync.service.ts | 53 ++++++++-- .../api/src/ticketing/user/types/index.ts | 1 + 28 files changed, 341 insertions(+), 52 deletions(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 1c88a0a7c..586a0981c 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -188,22 +188,22 @@ services: volumes: - .:/app - ngrok: - image: ngrok/ngrok:latest - restart: always - command: - - "start" - - "--all" - - "--config" - - "/etc/ngrok.yml" - volumes: - - ./ngrok.yml:/etc/ngrok.yml - ports: - - 4040:4040 - depends_on: - api: - condition: service_healthy - network_mode: "host" + #ngrok: + #image: ngrok/ngrok:latest + #restart: always + #command: + # - "start" + # - "--all" + # - "--config" + # - "/etc/ngrok.yml" + # volumes: + # - ./ngrok.yml:/etc/ngrok.yml + # ports: + # - 4040:4040 + #depends_on: + # api: + # condition: service_healthy + # network_mode: "host" docs: build: diff --git a/packages/api/src/ticketing/@webhook/handler.module.ts b/packages/api/src/ticketing/@webhook/handler.module.ts index 8d7be7332..dfb8fbf3e 100644 --- a/packages/api/src/ticketing/@webhook/handler.module.ts +++ b/packages/api/src/ticketing/@webhook/handler.module.ts @@ -5,9 +5,13 @@ import { TicketingWebhookHandlerService } from './handler.service'; import { ZendeskHandlerService } from './zendesk/handler'; import { EnvironmentService } from '@@core/environment/environment.service'; import { EncryptionService } from '@@core/encryption/encryption.service'; +import { TicketModule } from '@ticketing/ticket/ticket.module'; +import { UserModule } from '@ticketing/user/user.module'; +import { AccountModule } from '@ticketing/account/account.module'; +import { ContactModule } from '@ticketing/contact/contact.module'; @Module({ - imports: [], + imports: [TicketModule, UserModule, AccountModule, ContactModule], providers: [ PrismaService, LoggerService, diff --git a/packages/api/src/ticketing/@webhook/zendesk/handler.ts b/packages/api/src/ticketing/@webhook/zendesk/handler.ts index 2b49f5bb0..0d80e2058 100644 --- a/packages/api/src/ticketing/@webhook/zendesk/handler.ts +++ b/packages/api/src/ticketing/@webhook/zendesk/handler.ts @@ -4,9 +4,13 @@ import { LoggerService } from '@@core/logger/logger.service'; import { PrismaService } from '@@core/prisma/prisma.service'; import { Injectable } from '@nestjs/common'; import axios from 'axios'; -import { Payload } from './types'; import { mapToRemoteEvent } from './utils'; import * as crypto from 'crypto'; +import { NonTicketPayload, Payload } from './types'; +import { SyncService as TicketSyncService } from '@ticketing/ticket/sync/sync.service'; +import { SyncService as UserSyncService } from '@ticketing/user/sync/sync.service'; +import { SyncService as ContactSyncService } from '@ticketing/contact/sync/sync.service'; +import { SyncService as AccountSyncService } from '@ticketing/account/sync/sync.service'; @Injectable() export class ZendeskHandlerService { @@ -15,6 +19,10 @@ export class ZendeskHandlerService { private prisma: PrismaService, private cryptoService: EncryptionService, private env: EnvironmentService, + private syncTicketsService: TicketSyncService, + private syncUsersService: UserSyncService, + private syncContactsService: ContactSyncService, + private syncAccountsService: AccountSyncService, ) { this.logger.setContext(ZendeskHandlerService.name); } @@ -244,17 +252,104 @@ export class ZendeskHandlerService { payload, id_managed_webhook, ); + const mw = await this.prisma.managed_webhooks.findUnique({ + where: { + id_managed_webhook: id_managed_webhook, + }, + }); + const connection = await this.prisma.connections.findUnique({ + where: { + id_connection: mw.id_connection, + }, + }); if ('ticketId' in payload) { // ticket payload // TODO:update the tickzt inside our db + await this.syncTicketsService.syncTicketsForLinkedUser( + connection.provider_slug.toLowerCase(), + connection.id_linked_user, + connection.id_project, + { + action: 'UPDATE', + data: { remote_id: payload.ticketId as string }, + }, + ); } else { //non-ticket payload + const payload_ = payload as NonTicketPayload; + const [event_type, event_action] = this.extractValue(payload_.type); + switch (event_type) { + case 'user': + if (payload_.detail.role) { + if (payload_.detail.role == 'end-user') { + await this.syncContactsService.syncContactsForLinkedUser( + connection.provider_slug.toLowerCase(), + connection.id_linked_user, + connection.id_project, + payload_.detail.id, + { + action: + event_action.toLowerCase() == 'deleted' + ? 'DELETE' + : 'UPDATE', + data: { remote_id: payload_.detail.id as string }, + }, + ); + } else if ( + payload_.detail.role == 'admin' || + payload_.detail.role == 'agent' + ) { + await this.syncUsersService.syncUsersForLinkedUser( + connection.provider_slug.toLowerCase(), + connection.id_linked_user, + connection.id_project, + { + action: + event_action.toLowerCase() == 'deleted' + ? 'DELETE' + : 'UPDATE', + data: { remote_id: payload_.detail.id as string }, + }, + ); + } else { + break; + } + } + break; + case 'organization': + await this.syncAccountsService.syncAccountsForLinkedUser( + connection.provider_slug.toLowerCase(), + connection.id_linked_user, + connection.id_project, + { + action: + event_action.toLowerCase() == 'deleted' ? 'DELETE' : 'UPDATE', + data: { remote_id: payload_.detail.id as string }, + }, + ); + default: + break; + } } } catch (error) { throw new Error(error); } } + extractValue(typeString: string): string[] { + const prefix = 'zen:event-type:'; + const startIndex = typeString.indexOf(prefix); + + if (startIndex === -1) { + throw new Error('Prefix not found in the string.'); + } + + const afterPrefix = typeString.substring(startIndex + prefix.length); + const values = afterPrefix.split(':'); + return [values[0], values[1]]; + } + + async verifyWebhookAuthenticity( signature: string, timestamp: string, diff --git a/packages/api/src/ticketing/account/services/front/index.ts b/packages/api/src/ticketing/account/services/front/index.ts index 4295f41f5..307b86cf5 100644 --- a/packages/api/src/ticketing/account/services/front/index.ts +++ b/packages/api/src/ticketing/account/services/front/index.ts @@ -26,6 +26,7 @@ export class FrontService implements IAccountService { async syncAccounts( linkedUserId: string, + remote_account_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ diff --git a/packages/api/src/ticketing/account/services/zendesk/index.ts b/packages/api/src/ticketing/account/services/zendesk/index.ts index 895ffca17..4dcf1433c 100644 --- a/packages/api/src/ticketing/account/services/zendesk/index.ts +++ b/packages/api/src/ticketing/account/services/zendesk/index.ts @@ -28,7 +28,7 @@ export class ZendeskService implements IAccountService { async syncAccounts( linkedUserId: string, - custom_properties?: string[], + remote_account_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ @@ -38,9 +38,9 @@ export class ZendeskService implements IAccountService { vertical: 'ticketing', }, }); - + const request_url = remote_account_id ? `${connection.account_url}/organizations/${remote_account_id}.json` : `${connection.account_url}/organizations.json`; const resp = await axios.get( - `${connection.account_url}/organizations.json`, + request_url, { headers: { 'Content-Type': 'application/json', @@ -52,8 +52,10 @@ export class ZendeskService implements IAccountService { ); this.logger.log(`Synced zendesk accounts !`); + const result = remote_account_id ? [resp.data.organization] : resp.data.organizations; + return { - data: resp.data.organizations, + data: result, message: 'Zendesk accounts retrieved', statusCode: 200, }; diff --git a/packages/api/src/ticketing/account/sync/sync.service.ts b/packages/api/src/ticketing/account/sync/sync.service.ts index d97246851..608d95581 100644 --- a/packages/api/src/ticketing/account/sync/sync.service.ts +++ b/packages/api/src/ticketing/account/sync/sync.service.ts @@ -119,6 +119,12 @@ export class SyncService implements OnModuleInit { integrationId: string, linkedUserId: string, id_project: string, + wh_real_time_trigger?: { + action: 'UPDATE' | 'DELETE'; + data: { + remote_id: string; + }; + }, ) { try { this.logger.log( @@ -152,8 +158,28 @@ export class SyncService implements OnModuleInit { const service: IAccountService = this.serviceRegistry.getService(integrationId); - const resp: ApiResponse = - await service.syncAccounts(linkedUserId, remoteProperties); + + let resp: ApiResponse; + if (wh_real_time_trigger && wh_real_time_trigger.data.remote_id) { + //meaning the call has been from a real time webhook that received data from a 3rd party + switch (wh_real_time_trigger.action) { + case 'DELETE': + return await this.removeAccountInDb( + linkedUserId, + integrationId, + wh_real_time_trigger.data.remote_id, + ); + default: + resp = await service.syncAccounts( + linkedUserId, + wh_real_time_trigger.data.remote_id, + remoteProperties, + ); + break; + } + } else { + resp = await service.syncAccounts(linkedUserId, undefined, remoteProperties); + } const sourceObject: OriginalAccountOutput[] = resp.data; // this.logger.log('resp is ' + sourceObject); @@ -320,4 +346,23 @@ export class SyncService implements OnModuleInit { handleServiceError(error, this.logger); } } + + async removeAccountInDb( + linkedUserId: string, + originSource: string, + remote_id: string, + ) { + const existingAccount = await this.prisma.tcg_accounts.findFirst({ + where: { + remote_id: remote_id, + remote_platform: originSource, + id_linked_user: linkedUserId, + }, + }); + await this.prisma.tcg_accounts.delete({ + where: { + id_tcg_account: existingAccount.id_tcg_account, + }, + }); + } } diff --git a/packages/api/src/ticketing/account/types/index.ts b/packages/api/src/ticketing/account/types/index.ts index 3dfd21ba9..3e5238fad 100644 --- a/packages/api/src/ticketing/account/types/index.ts +++ b/packages/api/src/ticketing/account/types/index.ts @@ -6,6 +6,7 @@ import { ApiResponse } from '@@core/utils/types'; export interface IAccountService { syncAccounts( linkedUserId: string, + remote_account_id?: string, custom_properties?: string[], ): Promise>; } diff --git a/packages/api/src/ticketing/contact/services/front/index.ts b/packages/api/src/ticketing/contact/services/front/index.ts index 9b43dd9f7..2d745d0b3 100644 --- a/packages/api/src/ticketing/contact/services/front/index.ts +++ b/packages/api/src/ticketing/contact/services/front/index.ts @@ -26,7 +26,6 @@ export class FrontService implements IContactService { async syncContacts( linkedUserId: string, - unused_, remote_account_id: string, ): Promise> { try { diff --git a/packages/api/src/ticketing/contact/services/gorgias/index.ts b/packages/api/src/ticketing/contact/services/gorgias/index.ts index b788a7d7a..a6c1f5da2 100644 --- a/packages/api/src/ticketing/contact/services/gorgias/index.ts +++ b/packages/api/src/ticketing/contact/services/gorgias/index.ts @@ -26,7 +26,6 @@ export class GorgiasService implements IContactService { async syncContacts( linkedUserId: string, - unused_, remote_account_id: string, ): Promise> { try { diff --git a/packages/api/src/ticketing/contact/services/zendesk/index.ts b/packages/api/src/ticketing/contact/services/zendesk/index.ts index 6881b74e0..a9b9205a1 100644 --- a/packages/api/src/ticketing/contact/services/zendesk/index.ts +++ b/packages/api/src/ticketing/contact/services/zendesk/index.ts @@ -28,7 +28,7 @@ export class ZendeskService implements IContactService { async syncContacts( linkedUserId: string, - custom_properties?: string[], + remote_account_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ @@ -38,8 +38,9 @@ export class ZendeskService implements IContactService { vertical: 'ticketing', }, }); + const request_url = remote_account_id ? `${connection.account_url}/users/${remote_account_id}.json` : `${connection.account_url}/users.json`; - const resp = await axios.get(`${connection.account_url}/users`, { + const resp = await axios.get(request_url, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.cryptoService.decrypt( @@ -47,7 +48,8 @@ export class ZendeskService implements IContactService { )}`, }, }); - const contacts: ZendeskContactOutput[] = resp.data.users; + + const contacts: ZendeskContactOutput[] = remote_account_id ? [resp.data.user] : resp.data.users; const filteredContacts = contacts.filter( (contact) => contact.role === 'end-user', ); diff --git a/packages/api/src/ticketing/contact/sync/sync.service.ts b/packages/api/src/ticketing/contact/sync/sync.service.ts index c2a9fbe71..76fa023a9 100644 --- a/packages/api/src/ticketing/contact/sync/sync.service.ts +++ b/packages/api/src/ticketing/contact/sync/sync.service.ts @@ -132,6 +132,12 @@ export class SyncService implements OnModuleInit { linkedUserId: string, id_project: string, remote_account_id?: string, + wh_real_time_trigger?: { + action: 'UPDATE' | 'DELETE'; + data: { + remote_id: string; + }; + }, ) { try { this.logger.log( @@ -164,13 +170,27 @@ export class SyncService implements OnModuleInit { const service: IContactService = this.serviceRegistry.getService(integrationId); - const resp: ApiResponse = - await service.syncContacts( - linkedUserId, - remoteProperties, - remote_account_id, - ); - + let resp: ApiResponse; + if (wh_real_time_trigger && wh_real_time_trigger.data.remote_id) { + //meaning the call has been from a real time webhook that received data from a 3rd party + switch (wh_real_time_trigger.action) { + case 'DELETE': + return await this.removeContactInDb( + linkedUserId, + integrationId, + wh_real_time_trigger.data.remote_id, + ); + default: + resp = await service.syncContacts( + linkedUserId, + wh_real_time_trigger.data.remote_id, + remoteProperties, + ); + break; + } + } else { + resp = await service.syncContacts(linkedUserId, remote_account_id, remoteProperties); + } const sourceObject: OriginalContactOutput[] = resp.data; //unify the data according to the target obj wanted const unifiedObject = (await unify({ @@ -362,4 +382,22 @@ export class SyncService implements OnModuleInit { handleServiceError(error, this.logger); } } + async removeContactInDb( + linkedUserId: string, + originSource: string, + remote_id: string, + ) { + const existingContact = await this.prisma.tcg_contacts.findFirst({ + where: { + remote_id: remote_id, + remote_platform: originSource, + id_linked_user: linkedUserId, + }, + }); + await this.prisma.tcg_contacts.delete({ + where: { + id_tcg_contact: existingContact.id_tcg_contact, + }, + }); + } } diff --git a/packages/api/src/ticketing/contact/types/index.ts b/packages/api/src/ticketing/contact/types/index.ts index f26efcec7..8153fc4e2 100644 --- a/packages/api/src/ticketing/contact/types/index.ts +++ b/packages/api/src/ticketing/contact/types/index.ts @@ -6,8 +6,8 @@ import { OriginalContactOutput } from '@@core/utils/types/original/original.tick export interface IContactService { syncContacts( linkedUserId: string, - custom_properties?: string[], remote_account_id?: string, + custom_properties?: string[], ): Promise>; } diff --git a/packages/api/src/ticketing/ticket/services/front/index.ts b/packages/api/src/ticketing/ticket/services/front/index.ts index 5e05808a8..21da3df64 100644 --- a/packages/api/src/ticketing/ticket/services/front/index.ts +++ b/packages/api/src/ticketing/ticket/services/front/index.ts @@ -163,6 +163,7 @@ export class FrontService implements ITicketService { } async syncTickets( linkedUserId: string, + remote_ticket_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ diff --git a/packages/api/src/ticketing/ticket/services/github/index.ts b/packages/api/src/ticketing/ticket/services/github/index.ts index 4437a2f42..14d24e4e3 100644 --- a/packages/api/src/ticketing/ticket/services/github/index.ts +++ b/packages/api/src/ticketing/ticket/services/github/index.ts @@ -68,6 +68,7 @@ export class GithubService implements ITicketService { } async syncTickets( linkedUserId: string, + remote_ticket_id?: string, custom_properties?: string[], ): Promise> { try { diff --git a/packages/api/src/ticketing/ticket/services/gitlab/index.ts b/packages/api/src/ticketing/ticket/services/gitlab/index.ts index b3552c9df..3dbd8ae22 100644 --- a/packages/api/src/ticketing/ticket/services/gitlab/index.ts +++ b/packages/api/src/ticketing/ticket/services/gitlab/index.ts @@ -67,6 +67,7 @@ export class GitlabService implements ITicketService { } async syncTickets( linkedUserId: string, + remote_ticket_id?: string, custom_properties?: string[], ): Promise> { try { diff --git a/packages/api/src/ticketing/ticket/services/gorgias/index.ts b/packages/api/src/ticketing/ticket/services/gorgias/index.ts index 993b8412e..675916e28 100644 --- a/packages/api/src/ticketing/ticket/services/gorgias/index.ts +++ b/packages/api/src/ticketing/ticket/services/gorgias/index.ts @@ -106,6 +106,7 @@ export class GorgiasService implements ITicketService { async syncTickets( linkedUserId: string, + remote_ticket_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ diff --git a/packages/api/src/ticketing/ticket/services/hubspot/index.ts b/packages/api/src/ticketing/ticket/services/hubspot/index.ts index a4c408319..b2944b1bb 100644 --- a/packages/api/src/ticketing/ticket/services/hubspot/index.ts +++ b/packages/api/src/ticketing/ticket/services/hubspot/index.ts @@ -69,6 +69,7 @@ export class HubspotService implements ITicketService { } async syncTickets( linkedUserId: string, + remote_ticket_id?: string, custom_properties?: string[], ): Promise> { try { diff --git a/packages/api/src/ticketing/ticket/services/jira/index.ts b/packages/api/src/ticketing/ticket/services/jira/index.ts index 597bf3673..b0ef82e41 100644 --- a/packages/api/src/ticketing/ticket/services/jira/index.ts +++ b/packages/api/src/ticketing/ticket/services/jira/index.ts @@ -75,7 +75,8 @@ export class JiraService implements ITicketService { } async syncTickets( linkedUserId: string, - ): Promise> { + remote_ticket_id?: string, + ): Promise> { try { const connection = await this.prisma.connections.findFirst({ where: { diff --git a/packages/api/src/ticketing/ticket/services/zendesk/index.ts b/packages/api/src/ticketing/ticket/services/zendesk/index.ts index 4e1d93f04..6428e9f39 100644 --- a/packages/api/src/ticketing/ticket/services/zendesk/index.ts +++ b/packages/api/src/ticketing/ticket/services/zendesk/index.ts @@ -112,8 +112,10 @@ export class ZendeskService implements ITicketService { ); } } + async syncTickets( linkedUserId: string, + remote_ticket_id?: string, custom_properties?: string[], ): Promise> { try { @@ -125,7 +127,9 @@ export class ZendeskService implements ITicketService { }, }); - const resp = await axios.get(`${connection.account_url}/tickets/.json`, { + const request_url = remote_ticket_id ? `${connection.account_url}/tickets/${remote_ticket_id}.json` : `${connection.account_url}/tickets.json`; + + const resp = await axios.get(request_url, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.cryptoService.decrypt( @@ -135,8 +139,10 @@ export class ZendeskService implements ITicketService { }); this.logger.log(`Synced zendesk tickets !`); + const result = remote_ticket_id ? [resp.data.ticket] : resp.data.tickets; + return { - data: resp.data.tickets, + data: result, message: 'Zendesk tickets retrieved', statusCode: 200, }; @@ -151,5 +157,4 @@ export class ZendeskService implements ITicketService { } } - //todo: create a syncTicket(remote_ticket_id) } diff --git a/packages/api/src/ticketing/ticket/sync/sync.service.ts b/packages/api/src/ticketing/ticket/sync/sync.service.ts index d63dd428f..413327da1 100644 --- a/packages/api/src/ticketing/ticket/sync/sync.service.ts +++ b/packages/api/src/ticketing/ticket/sync/sync.service.ts @@ -119,6 +119,12 @@ export class SyncService implements OnModuleInit { integrationId: string, linkedUserId: string, id_project: string, + wh_real_time_trigger?: { + action: 'UPDATE' | 'DELETE'; + data: { + remote_id: string; + }; + }, ) { try { this.logger.log( @@ -151,8 +157,28 @@ export class SyncService implements OnModuleInit { const service: ITicketService = this.serviceRegistry.getService(integrationId); - const resp: ApiResponse = - await service.syncTickets(linkedUserId, remoteProperties); + + let resp: ApiResponse; + if (wh_real_time_trigger && wh_real_time_trigger.data.remote_id) { + //meaning the call has been from a real time webhook that received data from a 3rd party + switch (wh_real_time_trigger.action) { + case 'DELETE': + return await this.removeTicketInDb( + linkedUserId, + integrationId, + wh_real_time_trigger.data.remote_id, + ); + default: + resp = await service.syncTickets( + linkedUserId, + wh_real_time_trigger.data.remote_id, + remoteProperties, + ); + break; + } + } else { + resp = await service.syncTickets(linkedUserId, undefined, remoteProperties); + } const sourceObject: OriginalTicketOutput[] = resp.data; //this.logger.log('SOURCE OBJECT DATA = ' + JSON.stringify(sourceObject)); @@ -376,4 +402,22 @@ export class SyncService implements OnModuleInit { handleServiceError(error, this.logger); } } + async removeTicketInDb( + linkedUserId: string, + originSource: string, + remote_id: string, + ) { + const existingTicket = await this.prisma.tcg_tickets.findFirst({ + where: { + remote_id: remote_id, + remote_platform: originSource, + id_linked_user: linkedUserId, + }, + }); + await this.prisma.tcg_tickets.delete({ + where: { + id_tcg_ticket: existingTicket.id_tcg_ticket, + }, + }); + } } diff --git a/packages/api/src/ticketing/ticket/types/index.ts b/packages/api/src/ticketing/ticket/types/index.ts index 884514344..d9cb88d1c 100644 --- a/packages/api/src/ticketing/ticket/types/index.ts +++ b/packages/api/src/ticketing/ticket/types/index.ts @@ -11,6 +11,7 @@ export interface ITicketService { syncTickets( linkedUserId: string, + remote_ticket_id?: string, custom_properties?: string[], ): Promise>; } diff --git a/packages/api/src/ticketing/user/services/front/index.ts b/packages/api/src/ticketing/user/services/front/index.ts index b7f59f8bf..65133eff2 100644 --- a/packages/api/src/ticketing/user/services/front/index.ts +++ b/packages/api/src/ticketing/user/services/front/index.ts @@ -26,6 +26,7 @@ export class FrontService implements IUserService { async syncUsers( linkedUserId: string, + remote_user_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ diff --git a/packages/api/src/ticketing/user/services/gitlab/index.ts b/packages/api/src/ticketing/user/services/gitlab/index.ts index 15d1ff254..2c9ca3d58 100644 --- a/packages/api/src/ticketing/user/services/gitlab/index.ts +++ b/packages/api/src/ticketing/user/services/gitlab/index.ts @@ -26,6 +26,7 @@ export class GitlabService implements IUserService { async syncUsers( linkedUserId: string, + remote_user_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ diff --git a/packages/api/src/ticketing/user/services/gorgias/index.ts b/packages/api/src/ticketing/user/services/gorgias/index.ts index b04e7ae29..8ee271565 100644 --- a/packages/api/src/ticketing/user/services/gorgias/index.ts +++ b/packages/api/src/ticketing/user/services/gorgias/index.ts @@ -26,6 +26,7 @@ export class GorgiasService implements IUserService { async syncUsers( linkedUserId: string, + remote_user_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ diff --git a/packages/api/src/ticketing/user/services/jira/index.ts b/packages/api/src/ticketing/user/services/jira/index.ts index 61ac6baae..293649b1b 100644 --- a/packages/api/src/ticketing/user/services/jira/index.ts +++ b/packages/api/src/ticketing/user/services/jira/index.ts @@ -26,6 +26,7 @@ export class JiraService implements IUserService { async syncUsers( linkedUserId: string, + remote_user_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ diff --git a/packages/api/src/ticketing/user/services/zendesk/index.ts b/packages/api/src/ticketing/user/services/zendesk/index.ts index 8a855a9fb..c26156f92 100644 --- a/packages/api/src/ticketing/user/services/zendesk/index.ts +++ b/packages/api/src/ticketing/user/services/zendesk/index.ts @@ -28,7 +28,7 @@ export class ZendeskService implements IUserService { async syncUsers( linkedUserId: string, - custom_properties?: string[], + remote_user_id?: string, ): Promise> { try { const connection = await this.prisma.connections.findFirst({ @@ -38,8 +38,9 @@ export class ZendeskService implements IUserService { vertical: 'ticketing', }, }); + const request_url = remote_user_id ? `${connection.account_url}/users/${remote_user_id}.json` : `${connection.account_url}/users.json`; - const resp = await axios.get(`${connection.account_url}/users`, { + const resp = await axios.get(request_url, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.cryptoService.decrypt( @@ -48,7 +49,7 @@ export class ZendeskService implements IUserService { }, }); this.logger.log(`Synced zendesk users !`); - const users: ZendeskUserOutput[] = resp.data.users; + const users: ZendeskUserOutput[] = remote_user_id ? [resp.data.user] : resp.data.users; const filteredUsers = users.filter((user) => user.role === 'agent'); return { diff --git a/packages/api/src/ticketing/user/sync/sync.service.ts b/packages/api/src/ticketing/user/sync/sync.service.ts index c017a83ba..a19681194 100644 --- a/packages/api/src/ticketing/user/sync/sync.service.ts +++ b/packages/api/src/ticketing/user/sync/sync.service.ts @@ -119,6 +119,12 @@ export class SyncService implements OnModuleInit { integrationId: string, linkedUserId: string, id_project: string, + wh_real_time_trigger?: { + action: 'UPDATE' | 'DELETE'; + data: { + remote_id: string; + }; + }, ) { try { this.logger.log( @@ -151,10 +157,28 @@ export class SyncService implements OnModuleInit { const service: IUserService = this.serviceRegistry.getService(integrationId); - const resp: ApiResponse = await service.syncUsers( - linkedUserId, - remoteProperties, - ); + + let resp: ApiResponse; + if (wh_real_time_trigger && wh_real_time_trigger.data.remote_id) { + //meaning the call has been from a real time webhook that received data from a 3rd party + switch (wh_real_time_trigger.action) { + case 'DELETE': + return await this.removeUserInDb( + linkedUserId, + integrationId, + wh_real_time_trigger.data.remote_id, + ); + default: + resp = await service.syncUsers( + linkedUserId, + wh_real_time_trigger.data.remote_id, + remoteProperties, + ); + break; + } + } else { + resp = await service.syncUsers(linkedUserId, undefined, remoteProperties); + } const sourceObject: OriginalUserOutput[] = resp.data; // this.logger.log('SOURCE OBJECT DATA = ' + JSON.stringify(sourceObject)); @@ -168,8 +192,6 @@ export class SyncService implements OnModuleInit { customFieldMappings, })) as UnifiedUserOutput[]; - - //insert the data in the DB with the fieldMappings (value table) const user_data = await this.saveUsersInDb( linkedUserId, @@ -329,4 +351,23 @@ export class SyncService implements OnModuleInit { handleServiceError(error, this.logger); } } + + async removeUserInDb( + linkedUserId: string, + originSource: string, + remote_id: string, + ) { + const existingUser = await this.prisma.tcg_users.findFirst({ + where: { + remote_id: remote_id, + remote_platform: originSource, + id_linked_user: linkedUserId, + }, + }); + await this.prisma.tcg_users.delete({ + where: { + id_tcg_user: existingUser.id_tcg_user, + }, + }); + } } diff --git a/packages/api/src/ticketing/user/types/index.ts b/packages/api/src/ticketing/user/types/index.ts index b7b3e123c..dc6c75293 100644 --- a/packages/api/src/ticketing/user/types/index.ts +++ b/packages/api/src/ticketing/user/types/index.ts @@ -6,6 +6,7 @@ import { ApiResponse } from '@@core/utils/types'; export interface IUserService { syncUsers( linkedUserId: string, + remote_user_id?: string, custom_properties?: string[], ): Promise>; } From 16036ef1b9816718f6e4f1a7edc38cff086fdeb7 Mon Sep 17 00:00:00 2001 From: nael Date: Sat, 15 Jun 2024 12:25:19 +0200 Subject: [PATCH 2/3] :sparkles: Tested webhook --- .env.example | 3 +- .gitignore | 2 +- .../Connector/ConnectorDisplay.tsx | 79 +- docker-compose.dev.yml | 33 +- docker-compose.source.yml | 1 + docker-compose.yml | 1 + packages/api/scripts/connectorUpdate.js | 142 +- packages/api/scripts/init.sql | 3 +- .../@core/environment/environment.service.ts | 3 + .../src/ticketing/@webhook/zendesk/handler.ts | 22 +- packages/api/swagger/swagger-spec.json | 2284 +++++++++-------- 11 files changed, 1313 insertions(+), 1260 deletions(-) diff --git a/.env.example b/.env.example index a8186d383..0e53463c4 100644 --- a/.env.example +++ b/.env.example @@ -29,7 +29,8 @@ POSTGRES_USER=my_user POSTGRES_DB=panora_db POSTGRES_HOST=postgres POSTGRES_PASSWORD=my_password - +# Endpoint on which realtime webhooks are sent to +WEBHOOK_INGRESS=http://localhost:3000 # Each Provider is of form PROVIDER_VERTICAL_SOFTWAREMODE_ATTRIBUTE # ================================================ diff --git a/.gitignore b/.gitignore index 72a33af56..adcdcbf83 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ redis_data .DS_Store .pnpm-store/ .npmrc -.vscode \ No newline at end of file +.vscode diff --git a/apps/client-ts/src/components/Configuration/Connector/ConnectorDisplay.tsx b/apps/client-ts/src/components/Configuration/Connector/ConnectorDisplay.tsx index 64714dab0..1ac4f283f 100644 --- a/apps/client-ts/src/components/Configuration/Connector/ConnectorDisplay.tsx +++ b/apps/client-ts/src/components/Configuration/Connector/ConnectorDisplay.tsx @@ -8,7 +8,7 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from " import { PasswordInput } from "@/components/ui/password-input" import { z } from "zod" import config from "@/lib/config" -import { AuthStrategy, providerToType, Provider, extractProvider, extractVertical } from "@panora/shared" +import { AuthStrategy, providerToType, Provider, extractProvider, extractVertical, needsSubdomain } from "@panora/shared" import { useEffect, useState } from "react" import useProjectStore from "@/state/projectStore" import { usePostHog } from 'posthog-js/react' @@ -26,24 +26,27 @@ interface ItemDisplayProps { } const formSchema = z.object({ + subdomain: z.string({ + required_error: "Please Enter a Subdomain", + }).optional(), client_id : z.string({ required_error: "Please Enter a Client ID", - }), + }).optional(), client_secret : z.string({ required_error: "Please Enter a Client Secret", - }), + }).optional(), scope : z.string({ required_error: "Please Enter a scope", - }), + }).optional(), api_key: z.string({ required_error: "Please Enter a API Key", - }), + }).optional(), username: z.string({ required_error: "Please Enter Username", - }), + }).optional(), secret: z.string({ required_error: "Please Enter Secret", - }), + }).optional(), }) export function ConnectorDisplay({ item }: ItemDisplayProps) { @@ -62,6 +65,7 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { + subdomain: "", client_id: "", client_secret: "", scope: "", @@ -88,10 +92,11 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { }; function onSubmit(values: z.infer) { - const { client_id, client_secret, scope, api_key, secret, username } = values; + const { client_id, client_secret, scope, api_key, secret, username, subdomain } = values; const performUpdate = mappingConnectionStrategies && mappingConnectionStrategies.length > 0; switch (item?.authStrategy) { case AuthStrategy.oauth2: + const needs_subdomain = needsSubdomain(item.name.toLowerCase(), item.vertical!.toLowerCase()); if (client_id === "" || client_secret === "" || scope === "") { if (client_id === "") { form.setError("client_id", { "message": "Please Enter Client ID" }); @@ -104,6 +109,18 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { } break; } + if(needs_subdomain && subdomain == ""){ + form.setError("subdomain", { "message": "Please Enter Subdomain" }); + } + let ATTRIBUTES = []; + let VALUES = []; + if(needs_subdomain){ + ATTRIBUTES = ["subdomain", "client_id", "client_secret", "scope"], + VALUES = [subdomain!, client_id!, client_secret!, scope!] + }else{ + ATTRIBUTES = ["client_id", "client_secret", "scope"], + VALUES = [client_id!, client_secret!, scope!] + } if (performUpdate) { const dataToUpdate = mappingConnectionStrategies[0]; toast.promise( @@ -111,8 +128,8 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { id_cs: dataToUpdate.id_connection_strategy, updateToggle: false, status: dataToUpdate.status, - attributes: ["client_id", "client_secret", "scope"], - values: [client_id, client_secret, scope] + attributes: ATTRIBUTES, + values: VALUES }), { loading: 'Loading...', @@ -140,8 +157,8 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { toast.promise( createCsPromise({ type: providerToType(item?.name, item?.vertical!, AuthStrategy.oauth2), - attributes: ["client_id", "client_secret", "scope"], - values: [client_id, client_secret, scope] + attributes: ATTRIBUTES, + values: VALUES }), { loading: 'Loading...', @@ -183,7 +200,7 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { updateToggle: false, status: dataToUpdate.status, attributes: ["api_key"], - values: [api_key] + values: [api_key!] }), { loading: 'Loading...', @@ -212,7 +229,7 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { createCsPromise({ type: providerToType(item?.name, item?.vertical!, AuthStrategy.api_key), attributes: ["api_key"], - values: [api_key] + values: [api_key!] }), { loading: 'Loading...', @@ -259,7 +276,7 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { updateToggle: false, status: dataToUpdate.status, attributes: ["username", "secret"], - values: [username, secret] + values: [username!, secret!] }), { loading: 'Loading...', @@ -289,7 +306,7 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { createCsPromise({ type: providerToType(item?.name, item?.vertical!, AuthStrategy.basic), attributes: ["username", "secret"], - values: [username, secret] + values: [username!, secret!] }), { loading: 'Loading...', @@ -324,14 +341,19 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) { if (mappingConnectionStrategies && mappingConnectionStrategies.length > 0) { fetchCredentials({ type: mappingConnectionStrategies[0].type, - attributes: item?.authStrategy === AuthStrategy.oauth2 ? ["client_id", "client_secret", "scope"] + attributes: item?.authStrategy === AuthStrategy.oauth2 ? needsSubdomain(item.name.toLowerCase(), item.vertical!.toLowerCase()) ? ["subdomain", "client_id", "client_secret", "scope"] : ["client_id", "client_secret", "scope"] : item?.authStrategy === AuthStrategy.api_key ? ["api_key"] : ["username", "secret"] }, { onSuccess(data) { if (item?.authStrategy === AuthStrategy.oauth2) { - form.setValue("client_id", data[0]); - form.setValue("client_secret", data[1]); - form.setValue("scope", data[2]); + let i = 0; + if(needsSubdomain(item.name.toLowerCase(), item.vertical!.toLowerCase())){ + form.setValue("subdomain", data[i]); + i = 1; + } + form.setValue("client_id", data[i]); + form.setValue("client_secret", data[i + 1]); + form.setValue("scope", data[i + 2]); } if (item?.authStrategy === AuthStrategy.api_key) { form.setValue("api_key", data[0]); @@ -415,6 +437,23 @@ export function ConnectorDisplay({ item }: ItemDisplayProps) {
{ item.authStrategy == AuthStrategy.oauth2 && <> + { needsSubdomain(item.name.toLowerCase(), item.vertical!.toLowerCase()) && +
+ ( + + Subdomain + + + + + + )} + /> +
+ }
- !( - vertical === 'ticketing' && newServiceName.toLowerCase() === 'zendesk' - ), - ) - .forEach((newServiceName) => { + newServiceDirs.forEach((newServiceName) => { + if ( + !(vertical === 'ticketing' && newServiceName.toLowerCase() === 'zendesk') + ) { const serviceNameCapitalized = newServiceName.charAt(0).toUpperCase() + newServiceName.slice(1); const objectCapitalized = @@ -212,28 +208,26 @@ function updateMappingsFile( if (!mappingObjectContent.includes(` ${newServiceName}: {`)) { newMappings += mappingEntry; } - }); + } + }); // Combine updates with the original sections of the file content const updatedContentBeforeMapping = - beforeFirstImport + - newImports + - beforeMappingObject.trim() + - '\n\n' + - newInstances; + beforeFirstImport + newImports + beforeMappingObject.trim(); // Update the mapping object content with new mappings - const insertionPoint = mappingObjectContent.lastIndexOf('};'); const updatedMappingObjectContent = [ - mappingObjectContent.slice(0, insertionPoint), + mappingObjectContent.slice(0, mappingObjectContent.lastIndexOf('};')), newMappings, - mappingObjectContent.slice(insertionPoint), + mappingObjectContent.slice(mappingObjectContent.lastIndexOf('};')), ].join(''); // Reassemble the complete updated file content const updatedFileContent = - updatedContentBeforeMapping + updatedMappingObjectContent; - + updatedContentBeforeMapping + + '\n' + + newInstances + + updatedMappingObjectContent; // Write the updated content back to the file fs.writeFileSync(mappingsFile, updatedFileContent); } @@ -303,8 +297,10 @@ function updateEnumFile(enumFilePath, newServiceDirs, vertical) { let enumEntries = match[1] .trim() .split(/\n/) - .map((e) => e.trim()) - .filter((e) => e); + .map((entry) => entry.trim()) + .filter((entry) => entry.endsWith(',')) // Ensure all entries end with a comma + .map((entry) => entry.replace(/,$/, '')); // Remove commas for a clean slate + const existingEntries = enumEntries.map((entry) => entry.split('=')[0].trim(), ); @@ -314,10 +310,15 @@ function updateEnumFile(enumFilePath, newServiceDirs, vertical) { const enumEntryName = serviceName.toUpperCase(); // Assuming the enum entry name is the uppercase service name if (!existingEntries.includes(enumEntryName)) { // Format the new enum entry, assuming you want the name and value to be the same - enumEntries.push(`${enumEntryName} = '${serviceName}',`); + enumEntries.push(`${enumEntryName} = '${serviceName}'`); } }); + // Add commas back to all entries except the last one + enumEntries = enumEntries.map((entry, index, array) => + index === array.length - 1 ? entry : `${entry},`, + ); + // Rebuild the enum content const updatedEnumContent = `export enum ${enumName} {\n ${enumEntries.join( '\n ', @@ -348,17 +349,19 @@ function updateInitSQLFile(initSQLFile, newServiceDirs, vertical) { return; } - let newLines = ''; - newServiceDirs.forEach((serviceName) => { - const columnName = `${vertical.toLowerCase()}_${serviceName.toLowerCase()}`; - newLines += ` ${columnName} boolean NOT NULL,\n`; - }); + // Prepare new column lines to be inserted + let newLines = newServiceDirs + .map((serviceName) => { + const columnName = `${vertical.toLowerCase()}_${serviceName.toLowerCase()}`; + return ` ${columnName} boolean NOT NULL,\n`; + }) + .join(''); - fileContent = [ - fileContent.slice(0, insertPoint), - newLines, - fileContent.slice(insertPoint), - ].join(''); + // Insert the new column definitions just before the PRIMARY KEY constraint + fileContent = + fileContent.slice(0, insertPoint) + + newLines + + fileContent.slice(insertPoint); fs.writeFileSync(initSQLFile, fileContent); } @@ -367,46 +370,47 @@ function updateInitSQLFile(initSQLFile, newServiceDirs, vertical) { function updateSeedSQLFile(seedSQLFile, newServiceDirs, vertical) { let fileContent = fs.readFileSync(seedSQLFile, 'utf8'); - const tableInsertPoint = fileContent.indexOf('INSERT INTO connector_sets'); - if (tableInsertPoint === -1) { - console.error( - `Could not find the INSERT INTO connector_sets statement in ${seedSQLFile}`, - ); - return; + // Regex to find the INSERT statement for connector_sets + const regex = /INSERT INTO connector_sets \(([^)]+)\) VALUES/g; + let match; + let lastMatch; + while ((match = regex.exec(fileContent)) !== null) { + lastMatch = match; // Store the last match } - - const columnInsertPoint = fileContent.indexOf('(', tableInsertPoint); - const valuesInsertPoint = fileContent.indexOf('VALUES', columnInsertPoint); - const rowsInsertPoint = fileContent.indexOf('(', valuesInsertPoint); - - if ( - columnInsertPoint === -1 || - valuesInsertPoint === -1 || - rowsInsertPoint === -1 - ) { - console.error( - `Could not find the column or values insert points in ${seedSQLFile}`, - ); + if (!lastMatch) { + console.error('Could not find the INSERT INTO connector_sets statement.'); return; } - let newColumns = ''; - let newValues = ''; - newServiceDirs.forEach((serviceName) => { - const columnName = `${vertical.toLowerCase()}_${serviceName.toLowerCase()}`; - newColumns += `${columnName}, `; - newValues += 'TRUE, '; - }); - - const updatedFileContent = [ - fileContent.slice(0, columnInsertPoint + 1), - newColumns, - fileContent.slice(columnInsertPoint + 1, rowsInsertPoint + 1), - newValues, - fileContent.slice(rowsInsertPoint + 1), - ].join(''); + // Extracting columns and preparing to insert new ones + let columns = lastMatch[1].split(',').map((col) => col.trim()); + let newColumns = newServiceDirs.map( + (serviceName) => `${vertical.toLowerCase()}_${serviceName.toLowerCase()}`, + ); - fs.writeFileSync(seedSQLFile, updatedFileContent); + // Filter out existing new columns to avoid duplication + newColumns = newColumns.filter((nc) => !columns.includes(nc)); + if (newColumns.length > 0) { + // Insert new columns before the closing parenthesis in the columns list + columns = [...columns, ...newColumns]; + let newColumnsSection = columns.join(', '); + + // Replace the old columns section with the new one + fileContent = fileContent.replace(lastMatch[1], newColumnsSection); + + // Update each VALUES section + fileContent = fileContent.replace(/VALUES(.*?);/gs, (match) => { + return match + .replace(/\),\s*\(/g, '),\n (') // Fix line formatting + .replace(/\([^\)]+\)/g, (values) => { + let newValues = newColumns.map(() => 'TRUE').join(', '); + return values.slice(0, -1) + ', ' + newValues + ')'; + }); + }); + } + // Write the modified content back to the file + fs.writeFileSync(seedSQLFile, fileContent); + console.log('Seed SQL file has been updated successfully.'); } // Main script logic @@ -486,10 +490,10 @@ function updateObjectTypes(baseDir, objectType, vertical) { // Update SQL files const initSQLFile = path.join(__dirname, './init.sql'); - updateInitSQLFile(initSQLFile, newServiceDirs, slugFromCategory(vertical)); + updateInitSQLFile(initSQLFile, newProviders, slugFromCategory(vertical)); const seedSQLFile = path.join(__dirname, './seed.sql'); - updateSeedSQLFile(seedSQLFile, newServiceDirs, slugFromCategory(vertical)); + updateSeedSQLFile(seedSQLFile, newProviders, slugFromCategory(vertical)); } // Example usage for ticketing/team diff --git a/packages/api/scripts/init.sql b/packages/api/scripts/init.sql index 6eb0d80c0..30c8b1cc8 100644 --- a/packages/api/scripts/init.sql +++ b/packages/api/scripts/init.sql @@ -423,8 +423,6 @@ CREATE TABLE connector_sets tcg_gorgias boolean NOT NULL, tcg_gitlab boolean NOT NULL, tcg_front boolean NOT NULL, - crm_zendesk boolean NOT NULL, - crm_close boolean NOT NULL, CONSTRAINT PK_project_connector PRIMARY KEY ( id_connector_set ) ); @@ -583,6 +581,7 @@ CREATE TABLE fs_folders CREATE INDEX FK_fs_folder_driveID ON fs_folders ( id_fs_drive +); CREATE INDEX FK_fs_folder_permissionID ON fs_folders ( diff --git a/packages/api/src/@core/environment/environment.service.ts b/packages/api/src/@core/environment/environment.service.ts index 690e75a89..d28cbf1cf 100644 --- a/packages/api/src/@core/environment/environment.service.ts +++ b/packages/api/src/@core/environment/environment.service.ts @@ -20,6 +20,9 @@ export class EnvironmentService { getEnvMode(): string { return this.configService.get('ENV'); } + getWebhookIngress(): string { + return this.configService.get('WEBHOOK_INGRESS'); + } getSentryDsn(): string { return this.configService.get('SENTRY_DSN'); } diff --git a/packages/api/src/ticketing/@webhook/zendesk/handler.ts b/packages/api/src/ticketing/@webhook/zendesk/handler.ts index bb8589090..ac56dd518 100644 --- a/packages/api/src/ticketing/@webhook/zendesk/handler.ts +++ b/packages/api/src/ticketing/@webhook/zendesk/handler.ts @@ -63,15 +63,18 @@ export class ZendeskHandlerService { if (!conn) throw ReferenceError('Connection undefined'); const unified_events = mw.active_events; - const events_ = unified_events - .flatMap((event) => mapToRemoteEvent(event)) - .filter((item) => item !== null && item !== undefined); - + const events_ = Array.from( + new Set( + unified_events + .flatMap((event) => mapToRemoteEvent(event)) + .filter((item) => item !== null && item !== undefined), + ), + ); // Converts the Set back into an array const body_data = { webhook: { name: webhook_name, status: 'active', - endpoint: `${this.env.getPanoraBaseUrl()}/mw/${mw.endpoint}`, + endpoint: `${this.env.getWebhookIngress()}/mw/${mw.endpoint}`, http_method: 'POST', request_format: 'json', subscriptions: events_, @@ -150,7 +153,7 @@ export class ZendeskHandlerService { webhook: { name: webhook_name, status: 'active', - endpoint: `${this.env.getPanoraBaseUrl()}/mw/${mw.endpoint}`, + endpoint: `${this.env.getWebhookIngress()}/mw/${mw.endpoint}`, http_method: 'POST', request_format: 'json', subscriptions: ['conditional_ticket_events'], @@ -210,10 +213,6 @@ export class ZendeskHandlerService { field: 'priority', operator: 'changed', }, - { - field: 'status', - value: 'changed', - }, { field: 'update_type', value: 'Create', @@ -310,7 +309,7 @@ export class ZendeskHandlerService { action: 'UPDATE', data: { remote_id: payload.ticketId as string }, }, - ); + ); } else { //non-ticket payload const payload_ = payload as NonTicketPayload; @@ -393,7 +392,6 @@ export class ZendeskHandlerService { return [values[0], values[1]]; } - async verifyWebhookAuthenticity( signature: string, timestamp: string, diff --git a/packages/api/swagger/swagger-spec.json b/packages/api/swagger/swagger-spec.json index cbc4cc7e3..a266f957d 100644 --- a/packages/api/swagger/swagger-spec.json +++ b/packages/api/swagger/swagger-spec.json @@ -599,10 +599,10 @@ ] } }, - "/crm/companies": { + "/ticketing/tickets": { "get": { - "operationId": "getCompanies", - "summary": "List a batch of Companies", + "operationId": "getTickets", + "summary": "List a batch of Tickets", "parameters": [ { "name": "x-connection-token", @@ -655,7 +655,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCompanyOutput" + "$ref": "#/components/schemas/UnifiedTicketOutput" } } } @@ -666,7 +666,7 @@ } }, "tags": [ - "crm/companies" + "ticketing/tickets" ], "security": [ { @@ -675,9 +675,9 @@ ] }, "post": { - "operationId": "addCompany", - "summary": "Create a Company", - "description": "Create a company in any supported Crm software", + "operationId": "addTicket", + "summary": "Create a Ticket", + "description": "Create a ticket in any supported Ticketing software", "parameters": [ { "name": "x-connection-token", @@ -692,7 +692,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Crm software.", + "description": "Set to true to include data from the original Ticketing software.", "schema": { "type": "boolean" } @@ -703,7 +703,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedCompanyInput" + "$ref": "#/components/schemas/UnifiedTicketInput" } } } @@ -721,7 +721,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCompanyOutput" + "$ref": "#/components/schemas/UnifiedTicketOutput" } } } @@ -735,14 +735,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedCompanyOutput" + "$ref": "#/components/schemas/UnifiedTicketOutput" } } } } }, "tags": [ - "crm/companies" + "ticketing/tickets" ], "security": [ { @@ -751,8 +751,8 @@ ] }, "patch": { - "operationId": "updateCompany", - "summary": "Update a Company", + "operationId": "updateTicket", + "summary": "Update a Ticket", "parameters": [ { "name": "id", @@ -769,25 +769,14 @@ "content": { "application/json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/ApiResponse" - }, - { - "properties": { - "data": { - "$ref": "#/components/schemas/UnifiedCompanyOutput" - } - } - } - ] + "$ref": "#/components/schemas/UnifiedTicketOutput" } } } } }, "tags": [ - "crm/companies" + "ticketing/tickets" ], "security": [ { @@ -796,17 +785,17 @@ ] } }, - "/crm/companies/{id}": { + "/ticketing/tickets/{id}": { "get": { - "operationId": "getCompany", - "summary": "Retrieve a Company", - "description": "Retrieve a company from any connected Crm software", + "operationId": "getTicket", + "summary": "Retrieve a Ticket", + "description": "Retrieve a ticket from any connected Ticketing software", "parameters": [ { "name": "id", "required": true, "in": "path", - "description": "id of the company you want to retrieve.", + "description": "id of the `ticket` you want to retrive.", "schema": { "type": "string" } @@ -815,7 +804,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Crm software.", + "description": "Set to true to include data from the original Ticketing software.", "schema": { "type": "boolean" } @@ -834,7 +823,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCompanyOutput" + "$ref": "#/components/schemas/UnifiedTicketOutput" } } } @@ -845,7 +834,7 @@ } }, "tags": [ - "crm/companies" + "ticketing/tickets" ], "security": [ { @@ -854,10 +843,10 @@ ] } }, - "/crm/companies/batch": { + "/ticketing/tickets/batch": { "post": { - "operationId": "addCompanies", - "summary": "Add a batch of Companies", + "operationId": "addTickets", + "summary": "Add a batch of Tickets", "parameters": [ { "name": "x-connection-token", @@ -872,7 +861,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Crm software.", + "description": "Set to true to include data from the original Ticketing software.", "schema": { "type": "boolean" } @@ -885,7 +874,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedCompanyInput" + "$ref": "#/components/schemas/UnifiedTicketInput" } } } @@ -904,7 +893,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCompanyOutput" + "$ref": "#/components/schemas/UnifiedTicketOutput" } } } @@ -920,7 +909,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedCompanyOutput" + "$ref": "#/components/schemas/UnifiedTicketOutput" } } } @@ -928,7 +917,7 @@ } }, "tags": [ - "crm/companies" + "ticketing/tickets" ], "security": [ { @@ -937,10 +926,10 @@ ] } }, - "/crm/contacts": { + "/ticketing/users": { "get": { - "operationId": "getContacts", - "summary": "List a batch of CRM Contacts", + "operationId": "getUsers", + "summary": "List a batch of Users", "parameters": [ { "name": "x-connection-token", @@ -993,7 +982,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedContactOutput" + "$ref": "#/components/schemas/UnifiedUserOutput" } } } @@ -1004,24 +993,26 @@ } }, "tags": [ - "crm/contacts" + "ticketing/users" ], "security": [ { "JWT": [] } ] - }, - "post": { - "operationId": "addContact", - "summary": "Create CRM Contact", - "description": "Create a contact in any supported CRM", + } + }, + "/ticketing/users/{id}": { + "get": { + "operationId": "getUser", + "summary": "Retrieve a User", + "description": "Retrieve a user from any connected Ticketing software", "parameters": [ { - "name": "x-connection-token", + "name": "id", "required": true, - "in": "header", - "description": "The connection token", + "in": "path", + "description": "id of the user you want to retrieve.", "schema": { "type": "string" } @@ -1030,22 +1021,12 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original CRM software.", + "description": "Set to true to include data from the original Ticketing software.", "schema": { "type": "boolean" } } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnifiedContactInput" - } - } - } - }, "responses": { "200": { "description": "", @@ -1059,7 +1040,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedContactOutput" + "$ref": "#/components/schemas/UnifiedUserOutput" } } } @@ -1067,54 +1048,10 @@ } } } - }, - "201": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnifiedContactOutput" - } - } - } - } - }, - "tags": [ - "crm/contacts" - ], - "security": [ - { - "JWT": [] - } - ] - }, - "patch": { - "operationId": "updateContact", - "summary": "Update a CRM Contact", - "parameters": [ - { - "name": "id", - "required": true, - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnifiedContactOutput" - } - } - } } }, "tags": [ - "crm/contacts" + "ticketing/users" ], "security": [ { @@ -1123,17 +1060,16 @@ ] } }, - "/crm/contacts/{id}": { + "/ticketing/accounts": { "get": { - "operationId": "getContact", - "summary": "Retrieve a CRM Contact", - "description": "Retrieve a contact from any connected CRM", + "operationId": "getAccounts", + "summary": "List a batch of Accounts", "parameters": [ { - "name": "id", + "name": "x-connection-token", "required": true, - "in": "path", - "description": "id of the `contact` you want to retrive.", + "in": "header", + "description": "The connection token", "schema": { "type": "string" } @@ -1142,10 +1078,29 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original CRM software.", + "description": "Set to true to include data from the original software.", "schema": { "type": "boolean" } + }, + { + "name": "pageSize", + "required": false, + "in": "query", + "description": "Set to get the number of records.", + "schema": { + "default": 50, + "type": "number" + } + }, + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Set to get the number of records after this cursor.", + "schema": { + "type": "string" + } } ], "responses": { @@ -1161,7 +1116,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedContactOutput" + "$ref": "#/components/schemas/UnifiedAccountOutput" } } } @@ -1172,7 +1127,7 @@ } }, "tags": [ - "crm/contacts" + "ticketing/accounts" ], "security": [ { @@ -1181,16 +1136,17 @@ ] } }, - "/crm/contacts/batch": { - "post": { - "operationId": "addContacts", - "summary": "Add a batch of CRM Contacts", + "/ticketing/accounts/{id}": { + "get": { + "operationId": "getAccount", + "summary": "Retrieve an Account", + "description": "Retrieve an account from any connected Ticketing software", "parameters": [ { - "name": "x-connection-token", + "name": "id", "required": true, - "in": "header", - "description": "The connection token", + "in": "path", + "description": "id of the account you want to retrieve.", "schema": { "type": "string" } @@ -1199,25 +1155,12 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original CRM software.", + "description": "Set to true to include data from the original Ticketing software.", "schema": { "type": "boolean" } } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UnifiedContactInput" - } - } - } - } - }, "responses": { "200": { "description": "", @@ -1231,7 +1174,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedContactOutput" + "$ref": "#/components/schemas/UnifiedAccountOutput" } } } @@ -1239,23 +1182,10 @@ } } } - }, - "201": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UnifiedContactOutput" - } - } - } - } } }, "tags": [ - "crm/contacts" + "ticketing/accounts" ], "security": [ { @@ -1264,10 +1194,10 @@ ] } }, - "/crm/deals": { + "/ticketing/contacts": { "get": { - "operationId": "getDeals", - "summary": "List a batch of Deals", + "operationId": "getContacts", + "summary": "List a batch of Contacts", "parameters": [ { "name": "x-connection-token", @@ -1320,7 +1250,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedDealOutput" + "$ref": "#/components/schemas/UnifiedContactOutput" } } } @@ -1331,7 +1261,141 @@ } }, "tags": [ - "crm/deals" + "ticketing/contacts" + ], + "security": [ + { + "JWT": [] + } + ] + } + }, + "/ticketing/contacts/{id}": { + "get": { + "operationId": "getContact", + "summary": "Retrieve a Contact", + "description": "Retrieve a contact from any connected Ticketing software", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "id of the contact you want to retrieve.", + "schema": { + "type": "string" + } + }, + { + "name": "remote_data", + "required": false, + "in": "query", + "description": "Set to true to include data from the original Ticketing software.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/UnifiedContactOutput" + } + } + } + ] + } + } + } + } + }, + "tags": [ + "ticketing/contacts" + ], + "security": [ + { + "JWT": [] + } + ] + } + }, + "/crm/companies": { + "get": { + "operationId": "getCompanies", + "summary": "List a batch of Companies", + "parameters": [ + { + "name": "x-connection-token", + "required": true, + "in": "header", + "description": "The connection token", + "schema": { + "type": "string" + } + }, + { + "name": "remote_data", + "required": false, + "in": "query", + "description": "Set to true to include data from the original software.", + "schema": { + "type": "boolean" + } + }, + { + "name": "pageSize", + "required": false, + "in": "query", + "description": "Set to get the number of records.", + "schema": { + "default": 50, + "type": "number" + } + }, + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Set to get the number of records after this cursor.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/UnifiedCompanyOutput" + } + } + } + ] + } + } + } + } + }, + "tags": [ + "crm/companies" ], "security": [ { @@ -1340,9 +1404,9 @@ ] }, "post": { - "operationId": "addDeal", - "summary": "Create a Deal", - "description": "Create a deal in any supported Crm software", + "operationId": "addCompany", + "summary": "Create a Company", + "description": "Create a company in any supported Crm software", "parameters": [ { "name": "x-connection-token", @@ -1368,7 +1432,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedDealInput" + "$ref": "#/components/schemas/UnifiedCompanyInput" } } } @@ -1386,7 +1450,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedDealOutput" + "$ref": "#/components/schemas/UnifiedCompanyOutput" } } } @@ -1400,44 +1464,31 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedDealOutput" + "$ref": "#/components/schemas/UnifiedCompanyOutput" } } } } }, "tags": [ - "crm/deals" + "crm/companies" ], "security": [ { "JWT": [] } ] - } - }, - "/crm/deals/{id}": { - "get": { - "operationId": "getDeal", - "summary": "Retrieve a Deal", - "description": "Retrieve a deal from any connected Crm software", + }, + "patch": { + "operationId": "updateCompany", + "summary": "Update a Company", "parameters": [ { "name": "id", "required": true, - "in": "path", - "description": "id of the deal you want to retrieve.", - "schema": { - "type": "string" - } - }, - { - "name": "remote_data", - "required": false, "in": "query", - "description": "Set to true to include data from the original Crm software.", "schema": { - "type": "boolean" + "type": "string" } } ], @@ -1454,7 +1505,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedDealOutput" + "$ref": "#/components/schemas/UnifiedCompanyOutput" } } } @@ -1465,25 +1516,38 @@ } }, "tags": [ - "crm/deals" + "crm/companies" ], "security": [ { "JWT": [] } ] - }, - "patch": { - "operationId": "updateDeal", - "summary": "Update a Deal", + } + }, + "/crm/companies/{id}": { + "get": { + "operationId": "getCompany", + "summary": "Retrieve a Company", + "description": "Retrieve a company from any connected Crm software", "parameters": [ { "name": "id", "required": true, "in": "path", + "description": "id of the company you want to retrieve.", "schema": { "type": "string" } + }, + { + "name": "remote_data", + "required": false, + "in": "query", + "description": "Set to true to include data from the original Crm software.", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -1499,7 +1563,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedDealOutput" + "$ref": "#/components/schemas/UnifiedCompanyOutput" } } } @@ -1510,7 +1574,7 @@ } }, "tags": [ - "crm/deals" + "crm/companies" ], "security": [ { @@ -1519,10 +1583,10 @@ ] } }, - "/crm/deals/batch": { + "/crm/companies/batch": { "post": { - "operationId": "addDeals", - "summary": "Add a batch of Deals", + "operationId": "addCompanies", + "summary": "Add a batch of Companies", "parameters": [ { "name": "x-connection-token", @@ -1550,7 +1614,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedDealInput" + "$ref": "#/components/schemas/UnifiedCompanyInput" } } } @@ -1569,7 +1633,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedDealOutput" + "$ref": "#/components/schemas/UnifiedCompanyOutput" } } } @@ -1585,7 +1649,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedDealOutput" + "$ref": "#/components/schemas/UnifiedCompanyOutput" } } } @@ -1593,7 +1657,7 @@ } }, "tags": [ - "crm/deals" + "crm/companies" ], "security": [ { @@ -1602,10 +1666,10 @@ ] } }, - "/crm/engagements": { + "/crm/contacts": { "get": { - "operationId": "getEngagements", - "summary": "List a batch of Engagements", + "operationId": "getContacts", + "summary": "List a batch of CRM Contacts", "parameters": [ { "name": "x-connection-token", @@ -1658,7 +1722,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedEngagementOutput" + "$ref": "#/components/schemas/UnifiedContactOutput" } } } @@ -1669,7 +1733,7 @@ } }, "tags": [ - "crm/engagements" + "crm/contacts" ], "security": [ { @@ -1678,9 +1742,9 @@ ] }, "post": { - "operationId": "addEngagement", - "summary": "Create a Engagement", - "description": "Create a engagement in any supported Crm software", + "operationId": "addContact", + "summary": "Create CRM Contact", + "description": "Create a contact in any supported CRM", "parameters": [ { "name": "x-connection-token", @@ -1695,7 +1759,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Crm software.", + "description": "Set to true to include data from the original CRM software.", "schema": { "type": "boolean" } @@ -1706,7 +1770,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedEngagementInput" + "$ref": "#/components/schemas/UnifiedContactInput" } } } @@ -1724,7 +1788,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedEngagementOutput" + "$ref": "#/components/schemas/UnifiedContactOutput" } } } @@ -1738,14 +1802,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedEngagementOutput" + "$ref": "#/components/schemas/UnifiedContactOutput" } } } } }, "tags": [ - "crm/engagements" + "crm/contacts" ], "security": [ { @@ -1754,8 +1818,8 @@ ] }, "patch": { - "operationId": "updateEngagement", - "summary": "Update a Engagement", + "operationId": "updateContact", + "summary": "Update a CRM Contact", "parameters": [ { "name": "id", @@ -1772,25 +1836,14 @@ "content": { "application/json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/ApiResponse" - }, - { - "properties": { - "data": { - "$ref": "#/components/schemas/UnifiedEngagementOutput" - } - } - } - ] + "$ref": "#/components/schemas/UnifiedContactOutput" } } } } }, "tags": [ - "crm/engagements" + "crm/contacts" ], "security": [ { @@ -1799,17 +1852,17 @@ ] } }, - "/crm/engagements/{id}": { + "/crm/contacts/{id}": { "get": { - "operationId": "getEngagement", - "summary": "Retrieve a Engagement", - "description": "Retrieve a engagement from any connected Crm software", + "operationId": "getContact", + "summary": "Retrieve a CRM Contact", + "description": "Retrieve a contact from any connected CRM", "parameters": [ { "name": "id", "required": true, "in": "path", - "description": "id of the engagement you want to retrieve.", + "description": "id of the `contact` you want to retrive.", "schema": { "type": "string" } @@ -1818,7 +1871,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Crm software.", + "description": "Set to true to include data from the original CRM software.", "schema": { "type": "boolean" } @@ -1837,7 +1890,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedEngagementOutput" + "$ref": "#/components/schemas/UnifiedContactOutput" } } } @@ -1848,7 +1901,7 @@ } }, "tags": [ - "crm/engagements" + "crm/contacts" ], "security": [ { @@ -1857,10 +1910,10 @@ ] } }, - "/crm/engagements/batch": { + "/crm/contacts/batch": { "post": { - "operationId": "addEngagements", - "summary": "Add a batch of Engagements", + "operationId": "addContacts", + "summary": "Add a batch of CRM Contacts", "parameters": [ { "name": "x-connection-token", @@ -1875,7 +1928,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Crm software.", + "description": "Set to true to include data from the original CRM software.", "schema": { "type": "boolean" } @@ -1888,7 +1941,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedEngagementInput" + "$ref": "#/components/schemas/UnifiedContactInput" } } } @@ -1907,7 +1960,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedEngagementOutput" + "$ref": "#/components/schemas/UnifiedContactOutput" } } } @@ -1923,7 +1976,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedEngagementOutput" + "$ref": "#/components/schemas/UnifiedContactOutput" } } } @@ -1931,7 +1984,7 @@ } }, "tags": [ - "crm/engagements" + "crm/contacts" ], "security": [ { @@ -1940,10 +1993,10 @@ ] } }, - "/crm/notes": { + "/crm/deals": { "get": { - "operationId": "getNotes", - "summary": "List a batch of Notes", + "operationId": "getDeals", + "summary": "List a batch of Deals", "parameters": [ { "name": "x-connection-token", @@ -1996,7 +2049,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedNoteOutput" + "$ref": "#/components/schemas/UnifiedDealOutput" } } } @@ -2007,7 +2060,7 @@ } }, "tags": [ - "crm/notes" + "crm/deals" ], "security": [ { @@ -2016,9 +2069,9 @@ ] }, "post": { - "operationId": "addNote", - "summary": "Create a Note", - "description": "Create a note in any supported Crm software", + "operationId": "addDeal", + "summary": "Create a Deal", + "description": "Create a deal in any supported Crm software", "parameters": [ { "name": "x-connection-token", @@ -2044,7 +2097,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedNoteInput" + "$ref": "#/components/schemas/UnifiedDealInput" } } } @@ -2062,7 +2115,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedNoteOutput" + "$ref": "#/components/schemas/UnifiedDealOutput" } } } @@ -2076,14 +2129,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedNoteOutput" + "$ref": "#/components/schemas/UnifiedDealOutput" } } } } }, "tags": [ - "crm/notes" + "crm/deals" ], "security": [ { @@ -2092,17 +2145,17 @@ ] } }, - "/crm/notes/{id}": { + "/crm/deals/{id}": { "get": { - "operationId": "getNote", - "summary": "Retrieve a Note", - "description": "Retrieve a note from any connected Crm software", + "operationId": "getDeal", + "summary": "Retrieve a Deal", + "description": "Retrieve a deal from any connected Crm software", "parameters": [ { "name": "id", "required": true, "in": "path", - "description": "id of the note you want to retrieve.", + "description": "id of the deal you want to retrieve.", "schema": { "type": "string" } @@ -2130,7 +2183,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedNoteOutput" + "$ref": "#/components/schemas/UnifiedDealOutput" } } } @@ -2141,7 +2194,52 @@ } }, "tags": [ - "crm/notes" + "crm/deals" + ], + "security": [ + { + "JWT": [] + } + ] + }, + "patch": { + "operationId": "updateDeal", + "summary": "Update a Deal", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/UnifiedDealOutput" + } + } + } + ] + } + } + } + } + }, + "tags": [ + "crm/deals" ], "security": [ { @@ -2150,10 +2248,10 @@ ] } }, - "/crm/notes/batch": { + "/crm/deals/batch": { "post": { - "operationId": "addNotes", - "summary": "Add a batch of Notes", + "operationId": "addDeals", + "summary": "Add a batch of Deals", "parameters": [ { "name": "x-connection-token", @@ -2181,7 +2279,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedNoteInput" + "$ref": "#/components/schemas/UnifiedDealInput" } } } @@ -2200,7 +2298,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedNoteOutput" + "$ref": "#/components/schemas/UnifiedDealOutput" } } } @@ -2216,7 +2314,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedNoteOutput" + "$ref": "#/components/schemas/UnifiedDealOutput" } } } @@ -2224,7 +2322,7 @@ } }, "tags": [ - "crm/notes" + "crm/deals" ], "security": [ { @@ -2233,10 +2331,10 @@ ] } }, - "/crm/stages": { + "/crm/engagements": { "get": { - "operationId": "getStages", - "summary": "List a batch of Stages", + "operationId": "getEngagements", + "summary": "List a batch of Engagements", "parameters": [ { "name": "x-connection-token", @@ -2289,7 +2387,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedStageOutput" + "$ref": "#/components/schemas/UnifiedEngagementOutput" } } } @@ -2300,26 +2398,24 @@ } }, "tags": [ - "crm/stages" + "crm/engagements" ], "security": [ { "JWT": [] } ] - } - }, - "/crm/stages/{id}": { - "get": { - "operationId": "getStage", - "summary": "Retrieve a Stage", - "description": "Retrieve a stage from any connected Crm software", + }, + "post": { + "operationId": "addEngagement", + "summary": "Create a Engagement", + "description": "Create a engagement in any supported Crm software", "parameters": [ { - "name": "id", + "name": "x-connection-token", "required": true, - "in": "path", - "description": "id of the stage you want to retrieve.", + "in": "header", + "description": "The connection token", "schema": { "type": "string" } @@ -2334,6 +2430,16 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnifiedEngagementInput" + } + } + } + }, "responses": { "200": { "description": "", @@ -2347,7 +2453,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedStageOutput" + "$ref": "#/components/schemas/UnifiedEngagementOutput" } } } @@ -2355,56 +2461,35 @@ } } } + }, + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnifiedEngagementOutput" + } + } + } } }, "tags": [ - "crm/stages" + "crm/engagements" ], "security": [ { "JWT": [] } ] - } - }, - "/crm/tasks": { - "get": { - "operationId": "getTasks", - "summary": "List a batch of Tasks", + }, + "patch": { + "operationId": "updateEngagement", + "summary": "Update a Engagement", "parameters": [ { - "name": "x-connection-token", + "name": "id", "required": true, - "in": "header", - "description": "The connection token", - "schema": { - "type": "string" - } - }, - { - "name": "remote_data", - "required": false, - "in": "query", - "description": "Set to true to include data from the original software.", - "schema": { - "type": "boolean" - } - }, - { - "name": "pageSize", - "required": false, - "in": "query", - "description": "Set to get the number of records.", - "schema": { - "default": 50, - "type": "number" - } - }, - { - "name": "cursor", - "required": false, "in": "query", - "description": "Set to get the number of records after this cursor.", "schema": { "type": "string" } @@ -2423,7 +2508,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTaskOutput" + "$ref": "#/components/schemas/UnifiedEngagementOutput" } } } @@ -2434,24 +2519,26 @@ } }, "tags": [ - "crm/tasks" + "crm/engagements" ], "security": [ { "JWT": [] } ] - }, - "post": { - "operationId": "addTask", - "summary": "Create a Task", - "description": "Create a task in any supported Crm software", + } + }, + "/crm/engagements/{id}": { + "get": { + "operationId": "getEngagement", + "summary": "Retrieve a Engagement", + "description": "Retrieve a engagement from any connected Crm software", "parameters": [ { - "name": "x-connection-token", + "name": "id", "required": true, - "in": "header", - "description": "The connection token", + "in": "path", + "description": "id of the engagement you want to retrieve.", "schema": { "type": "string" } @@ -2466,16 +2553,6 @@ } } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnifiedTaskInput" - } - } - } - }, "responses": { "200": { "description": "", @@ -2489,7 +2566,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTaskOutput" + "$ref": "#/components/schemas/UnifiedEngagementOutput" } } } @@ -2497,40 +2574,55 @@ } } } - }, - "201": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnifiedTaskOutput" - } - } - } } }, "tags": [ - "crm/tasks" + "crm/engagements" ], "security": [ { "JWT": [] } ] - }, - "patch": { - "operationId": "updateTask", - "summary": "Update a Task", + } + }, + "/crm/engagements/batch": { + "post": { + "operationId": "addEngagements", + "summary": "Add a batch of Engagements", "parameters": [ { - "name": "id", + "name": "x-connection-token", "required": true, - "in": "query", + "in": "header", + "description": "The connection token", "schema": { "type": "string" } + }, + { + "name": "remote_data", + "required": false, + "in": "query", + "description": "Set to true to include data from the original Crm software.", + "schema": { + "type": "boolean" + } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnifiedEngagementInput" + } + } + } + } + }, "responses": { "200": { "description": "", @@ -2544,7 +2636,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTaskOutput" + "$ref": "#/components/schemas/UnifiedEngagementOutput" } } } @@ -2552,10 +2644,23 @@ } } } + }, + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnifiedEngagementOutput" + } + } + } + } } }, "tags": [ - "crm/tasks" + "crm/engagements" ], "security": [ { @@ -2564,17 +2669,16 @@ ] } }, - "/crm/tasks/{id}": { + "/crm/notes": { "get": { - "operationId": "getTask", - "summary": "Retrieve a Task", - "description": "Retrieve a task from any connected Crm software", + "operationId": "getNotes", + "summary": "List a batch of Notes", "parameters": [ { - "name": "id", + "name": "x-connection-token", "required": true, - "in": "path", - "description": "id of the task you want to retrieve.", + "in": "header", + "description": "The connection token", "schema": { "type": "string" } @@ -2583,10 +2687,29 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Crm software.", + "description": "Set to true to include data from the original software.", "schema": { "type": "boolean" } + }, + { + "name": "pageSize", + "required": false, + "in": "query", + "description": "Set to get the number of records.", + "schema": { + "default": 50, + "type": "number" + } + }, + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Set to get the number of records after this cursor.", + "schema": { + "type": "string" + } } ], "responses": { @@ -2602,7 +2725,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTaskOutput" + "$ref": "#/components/schemas/UnifiedNoteOutput" } } } @@ -2613,19 +2736,18 @@ } }, "tags": [ - "crm/tasks" + "crm/notes" ], "security": [ { "JWT": [] } ] - } - }, - "/crm/tasks/batch": { + }, "post": { - "operationId": "addTasks", - "summary": "Add a batch of Tasks", + "operationId": "addNote", + "summary": "Create a Note", + "description": "Create a note in any supported Crm software", "parameters": [ { "name": "x-connection-token", @@ -2651,10 +2773,7 @@ "content": { "application/json": { "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UnifiedTaskInput" - } + "$ref": "#/components/schemas/UnifiedNoteInput" } } } @@ -2672,7 +2791,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTaskOutput" + "$ref": "#/components/schemas/UnifiedNoteOutput" } } } @@ -2686,17 +2805,14 @@ "content": { "application/json": { "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UnifiedTaskOutput" - } + "$ref": "#/components/schemas/UnifiedNoteOutput" } } } } }, "tags": [ - "crm/tasks" + "crm/notes" ], "security": [ { @@ -2705,16 +2821,17 @@ ] } }, - "/crm/users": { + "/crm/notes/{id}": { "get": { - "operationId": "getUsers", - "summary": "List a batch of Users", + "operationId": "getNote", + "summary": "Retrieve a Note", + "description": "Retrieve a note from any connected Crm software", "parameters": [ { - "name": "x-connection-token", + "name": "id", "required": true, - "in": "header", - "description": "The connection token", + "in": "path", + "description": "id of the note you want to retrieve.", "schema": { "type": "string" } @@ -2723,29 +2840,10 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original software.", + "description": "Set to true to include data from the original Crm software.", "schema": { "type": "boolean" } - }, - { - "name": "pageSize", - "required": false, - "in": "query", - "description": "Set to get the number of records.", - "schema": { - "default": 50, - "type": "number" - } - }, - { - "name": "cursor", - "required": false, - "in": "query", - "description": "Set to get the number of records after this cursor.", - "schema": { - "type": "string" - } } ], "responses": { @@ -2761,7 +2859,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedUserOutput" + "$ref": "#/components/schemas/UnifiedNoteOutput" } } } @@ -2772,7 +2870,7 @@ } }, "tags": [ - "crm/users" + "crm/notes" ], "security": [ { @@ -2781,17 +2879,16 @@ ] } }, - "/crm/users/{id}": { - "get": { - "operationId": "getUser", - "summary": "Retrieve a User", - "description": "Retrieve a user from any connected Crm software", + "/crm/notes/batch": { + "post": { + "operationId": "addNotes", + "summary": "Add a batch of Notes", "parameters": [ { - "name": "id", + "name": "x-connection-token", "required": true, - "in": "path", - "description": "id of the user you want to retrieve.", + "in": "header", + "description": "The connection token", "schema": { "type": "string" } @@ -2806,6 +2903,19 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnifiedNoteInput" + } + } + } + } + }, "responses": { "200": { "description": "", @@ -2819,7 +2929,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedUserOutput" + "$ref": "#/components/schemas/UnifiedNoteOutput" } } } @@ -2827,10 +2937,23 @@ } } } + }, + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnifiedNoteOutput" + } + } + } + } } }, "tags": [ - "crm/users" + "crm/notes" ], "security": [ { @@ -2839,10 +2962,10 @@ ] } }, - "/ticketing/accounts": { + "/crm/stages": { "get": { - "operationId": "getAccounts", - "summary": "List a batch of Accounts", + "operationId": "getStages", + "summary": "List a batch of Stages", "parameters": [ { "name": "x-connection-token", @@ -2895,7 +3018,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedAccountOutput" + "$ref": "#/components/schemas/UnifiedStageOutput" } } } @@ -2906,7 +3029,7 @@ } }, "tags": [ - "ticketing/accounts" + "crm/stages" ], "security": [ { @@ -2915,17 +3038,17 @@ ] } }, - "/ticketing/accounts/{id}": { + "/crm/stages/{id}": { "get": { - "operationId": "getAccount", - "summary": "Retrieve an Account", - "description": "Retrieve an account from any connected Ticketing software", + "operationId": "getStage", + "summary": "Retrieve a Stage", + "description": "Retrieve a stage from any connected Crm software", "parameters": [ { "name": "id", "required": true, "in": "path", - "description": "id of the account you want to retrieve.", + "description": "id of the stage you want to retrieve.", "schema": { "type": "string" } @@ -2934,7 +3057,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Ticketing software.", + "description": "Set to true to include data from the original Crm software.", "schema": { "type": "boolean" } @@ -2953,7 +3076,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedAccountOutput" + "$ref": "#/components/schemas/UnifiedStageOutput" } } } @@ -2964,7 +3087,7 @@ } }, "tags": [ - "ticketing/accounts" + "crm/stages" ], "security": [ { @@ -2973,10 +3096,10 @@ ] } }, - "/ticketing/collections": { + "/crm/tasks": { "get": { - "operationId": "getCollections", - "summary": "List a batch of Collections", + "operationId": "getTasks", + "summary": "List a batch of Tasks", "parameters": [ { "name": "x-connection-token", @@ -3029,7 +3152,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCollectionOutput" + "$ref": "#/components/schemas/UnifiedTaskOutput" } } } @@ -3040,26 +3163,24 @@ } }, "tags": [ - "ticketing/collections" + "crm/tasks" ], "security": [ { "JWT": [] } ] - } - }, - "/ticketing/collections/{id}": { - "get": { - "operationId": "getCollection", - "summary": "Retrieve a Collection", - "description": "Retrieve a collection from any connected Ticketing software", + }, + "post": { + "operationId": "addTask", + "summary": "Create a Task", + "description": "Create a task in any supported Crm software", "parameters": [ { - "name": "id", + "name": "x-connection-token", "required": true, - "in": "path", - "description": "id of the collection you want to retrieve.", + "in": "header", + "description": "The connection token", "schema": { "type": "string" } @@ -3068,12 +3189,22 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Ticketing software.", + "description": "Set to true to include data from the original Crm software.", "schema": { "type": "boolean" } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnifiedTaskInput" + } + } + } + }, "responses": { "200": { "description": "", @@ -3087,7 +3218,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCollectionOutput" + "$ref": "#/components/schemas/UnifiedTaskOutput" } } } @@ -3095,86 +3226,20 @@ } } } - } - }, - "tags": [ - "ticketing/collections" - ], - "security": [ - { - "JWT": [] - } - ] - } - }, - "/ticketing/comments": { - "get": { - "operationId": "getComments", - "summary": "List a batch of Comments", - "parameters": [ - { - "name": "x-connection-token", - "required": true, - "in": "header", - "description": "The connection token", - "schema": { - "type": "string" - } - }, - { - "name": "remote_data", - "required": false, - "in": "query", - "description": "Set to true to include data from the original software.", - "schema": { - "type": "boolean" - } - }, - { - "name": "pageSize", - "required": false, - "in": "query", - "description": "Set to get the number of records.", - "schema": { - "default": 50, - "type": "number" - } }, - { - "name": "cursor", - "required": false, - "in": "query", - "description": "Set to get the number of records after this cursor.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { + "201": { "description": "", "content": { "application/json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/ApiResponse" - }, - { - "properties": { - "data": { - "$ref": "#/components/schemas/UnifiedCommentOutput" - } - } - } - ] + "$ref": "#/components/schemas/UnifiedTaskOutput" } } } } }, "tags": [ - "ticketing/comments" + "crm/tasks" ], "security": [ { @@ -3182,40 +3247,19 @@ } ] }, - "post": { - "operationId": "addComment", - "summary": "Create a Comment", - "description": "Create a comment in any supported Ticketing software", + "patch": { + "operationId": "updateTask", + "summary": "Update a Task", "parameters": [ { - "name": "x-connection-token", + "name": "id", "required": true, - "in": "header", - "description": "The connection token", - "schema": { - "type": "string" - } - }, - { - "name": "remote_data", - "required": false, "in": "query", - "description": "Set to true to include data from the original Ticketing software.", "schema": { - "type": "boolean" + "type": "string" } } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnifiedCommentInput" - } - } - } - }, "responses": { "200": { "description": "", @@ -3229,7 +3273,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCommentOutput" + "$ref": "#/components/schemas/UnifiedTaskOutput" } } } @@ -3237,20 +3281,10 @@ } } } - }, - "201": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnifiedCommentOutput" - } - } - } } }, "tags": [ - "ticketing/comments" + "crm/tasks" ], "security": [ { @@ -3259,17 +3293,17 @@ ] } }, - "/ticketing/comments/{id}": { + "/crm/tasks/{id}": { "get": { - "operationId": "getComment", - "summary": "Retrieve a Comment", - "description": "Retrieve a comment from any connected Ticketing software", + "operationId": "getTask", + "summary": "Retrieve a Task", + "description": "Retrieve a task from any connected Crm software", "parameters": [ { "name": "id", "required": true, "in": "path", - "description": "id of the `comment` you want to retrive.", + "description": "id of the task you want to retrieve.", "schema": { "type": "string" } @@ -3278,7 +3312,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Ticketing software.", + "description": "Set to true to include data from the original Crm software.", "schema": { "type": "boolean" } @@ -3297,7 +3331,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCommentOutput" + "$ref": "#/components/schemas/UnifiedTaskOutput" } } } @@ -3308,7 +3342,7 @@ } }, "tags": [ - "ticketing/comments" + "crm/tasks" ], "security": [ { @@ -3317,10 +3351,10 @@ ] } }, - "/ticketing/comments/batch": { + "/crm/tasks/batch": { "post": { - "operationId": "addComments", - "summary": "Add a batch of Comments", + "operationId": "addTasks", + "summary": "Add a batch of Tasks", "parameters": [ { "name": "x-connection-token", @@ -3335,7 +3369,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Ticketing software.", + "description": "Set to true to include data from the original Crm software.", "schema": { "type": "boolean" } @@ -3348,7 +3382,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedCommentInput" + "$ref": "#/components/schemas/UnifiedTaskInput" } } } @@ -3367,7 +3401,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedCommentOutput" + "$ref": "#/components/schemas/UnifiedTaskOutput" } } } @@ -3383,7 +3417,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/UnifiedCommentOutput" + "$ref": "#/components/schemas/UnifiedTaskOutput" } } } @@ -3391,7 +3425,7 @@ } }, "tags": [ - "ticketing/comments" + "crm/tasks" ], "security": [ { @@ -3400,10 +3434,10 @@ ] } }, - "/ticketing/contacts": { + "/crm/users": { "get": { - "operationId": "getContacts", - "summary": "List a batch of Contacts", + "operationId": "getUsers", + "summary": "List a batch of Users", "parameters": [ { "name": "x-connection-token", @@ -3456,7 +3490,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedContactOutput" + "$ref": "#/components/schemas/UnifiedUserOutput" } } } @@ -3467,7 +3501,7 @@ } }, "tags": [ - "ticketing/contacts" + "crm/users" ], "security": [ { @@ -3476,17 +3510,17 @@ ] } }, - "/ticketing/contacts/{id}": { + "/crm/users/{id}": { "get": { - "operationId": "getContact", - "summary": "Retrieve a Contact", - "description": "Retrieve a contact from any connected Ticketing software", + "operationId": "getUser", + "summary": "Retrieve a User", + "description": "Retrieve a user from any connected Crm software", "parameters": [ { "name": "id", "required": true, "in": "path", - "description": "id of the contact you want to retrieve.", + "description": "id of the user you want to retrieve.", "schema": { "type": "string" } @@ -3495,7 +3529,7 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Ticketing software.", + "description": "Set to true to include data from the original Crm software.", "schema": { "type": "boolean" } @@ -3514,7 +3548,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedContactOutput" + "$ref": "#/components/schemas/UnifiedUserOutput" } } } @@ -3525,7 +3559,7 @@ } }, "tags": [ - "ticketing/contacts" + "crm/users" ], "security": [ { @@ -3534,10 +3568,10 @@ ] } }, - "/ticketing/tags": { + "/ticketing/collections": { "get": { - "operationId": "getTags", - "summary": "List a batch of Tags", + "operationId": "getCollections", + "summary": "List a batch of Collections", "parameters": [ { "name": "x-connection-token", @@ -3590,7 +3624,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTagOutput" + "$ref": "#/components/schemas/UnifiedCollectionOutput" } } } @@ -3601,7 +3635,7 @@ } }, "tags": [ - "ticketing/tags" + "ticketing/collections" ], "security": [ { @@ -3610,17 +3644,17 @@ ] } }, - "/ticketing/tags/{id}": { + "/ticketing/collections/{id}": { "get": { - "operationId": "getTag", - "summary": "Retrieve a Tag", - "description": "Retrieve a tag from any connected Ticketing software", + "operationId": "getCollection", + "summary": "Retrieve a Collection", + "description": "Retrieve a collection from any connected Ticketing software", "parameters": [ { "name": "id", "required": true, "in": "path", - "description": "id of the tag you want to retrieve.", + "description": "id of the collection you want to retrieve.", "schema": { "type": "string" } @@ -3648,7 +3682,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTagOutput" + "$ref": "#/components/schemas/UnifiedCollectionOutput" } } } @@ -3659,7 +3693,7 @@ } }, "tags": [ - "ticketing/tags" + "ticketing/collections" ], "security": [ { @@ -3668,10 +3702,10 @@ ] } }, - "/ticketing/teams": { + "/ticketing/comments": { "get": { - "operationId": "getTeams", - "summary": "List a batch of Teams", + "operationId": "getComments", + "summary": "List a batch of Comments", "parameters": [ { "name": "x-connection-token", @@ -3724,7 +3758,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTeamOutput" + "$ref": "#/components/schemas/UnifiedCommentOutput" } } } @@ -3735,26 +3769,24 @@ } }, "tags": [ - "ticketing/teams" + "ticketing/comments" ], "security": [ { "JWT": [] } ] - } - }, - "/ticketing/teams/{id}": { - "get": { - "operationId": "getTeam", - "summary": "Retrieve a Team", - "description": "Retrieve a team from any connected Ticketing software", + }, + "post": { + "operationId": "addComment", + "summary": "Create a Comment", + "description": "Create a comment in any supported Ticketing software", "parameters": [ { - "name": "id", + "name": "x-connection-token", "required": true, - "in": "path", - "description": "id of the team you want to retrieve.", + "in": "header", + "description": "The connection token", "schema": { "type": "string" } @@ -3769,6 +3801,16 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnifiedCommentInput" + } + } + } + }, "responses": { "200": { "description": "", @@ -3782,7 +3824,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTeamOutput" + "$ref": "#/components/schemas/UnifiedCommentOutput" } } } @@ -3790,10 +3832,20 @@ } } } + }, + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnifiedCommentOutput" + } + } + } } }, "tags": [ - "ticketing/teams" + "ticketing/comments" ], "security": [ { @@ -3802,16 +3854,17 @@ ] } }, - "/ticketing/tickets": { + "/ticketing/comments/{id}": { "get": { - "operationId": "getTickets", - "summary": "List a batch of Tickets", + "operationId": "getComment", + "summary": "Retrieve a Comment", + "description": "Retrieve a comment from any connected Ticketing software", "parameters": [ { - "name": "x-connection-token", + "name": "id", "required": true, - "in": "header", - "description": "The connection token", + "in": "path", + "description": "id of the `comment` you want to retrive.", "schema": { "type": "string" } @@ -3820,29 +3873,10 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original software.", + "description": "Set to true to include data from the original Ticketing software.", "schema": { "type": "boolean" } - }, - { - "name": "pageSize", - "required": false, - "in": "query", - "description": "Set to get the number of records.", - "schema": { - "default": 50, - "type": "number" - } - }, - { - "name": "cursor", - "required": false, - "in": "query", - "description": "Set to get the number of records after this cursor.", - "schema": { - "type": "string" - } } ], "responses": { @@ -3858,7 +3892,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTicketOutput" + "$ref": "#/components/schemas/UnifiedCommentOutput" } } } @@ -3869,18 +3903,19 @@ } }, "tags": [ - "ticketing/tickets" + "ticketing/comments" ], "security": [ { "JWT": [] } ] - }, + } + }, + "/ticketing/comments/batch": { "post": { - "operationId": "addTicket", - "summary": "Create a Ticket", - "description": "Create a ticket in any supported Ticketing software", + "operationId": "addComments", + "summary": "Add a batch of Comments", "parameters": [ { "name": "x-connection-token", @@ -3906,7 +3941,10 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedTicketInput" + "type": "array", + "items": { + "$ref": "#/components/schemas/UnifiedCommentInput" + } } } } @@ -3924,7 +3962,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTicketOutput" + "$ref": "#/components/schemas/UnifiedCommentOutput" } } } @@ -3938,48 +3976,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UnifiedTicketOutput" - } - } - } - } - }, - "tags": [ - "ticketing/tickets" - ], - "security": [ - { - "JWT": [] - } - ] - }, - "patch": { - "operationId": "updateTicket", - "summary": "Update a Ticket", - "parameters": [ - { - "name": "id", - "required": true, - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnifiedTicketOutput" + "type": "array", + "items": { + "$ref": "#/components/schemas/UnifiedCommentOutput" + } } } } } }, "tags": [ - "ticketing/tickets" + "ticketing/comments" ], "security": [ { @@ -3988,17 +3995,16 @@ ] } }, - "/ticketing/tickets/{id}": { + "/ticketing/tags": { "get": { - "operationId": "getTicket", - "summary": "Retrieve a Ticket", - "description": "Retrieve a ticket from any connected Ticketing software", + "operationId": "getTags", + "summary": "List a batch of Tags", "parameters": [ { - "name": "id", + "name": "x-connection-token", "required": true, - "in": "path", - "description": "id of the `ticket` you want to retrive.", + "in": "header", + "description": "The connection token", "schema": { "type": "string" } @@ -4007,10 +4013,29 @@ "name": "remote_data", "required": false, "in": "query", - "description": "Set to true to include data from the original Ticketing software.", + "description": "Set to true to include data from the original software.", "schema": { "type": "boolean" } + }, + { + "name": "pageSize", + "required": false, + "in": "query", + "description": "Set to get the number of records.", + "schema": { + "default": 50, + "type": "number" + } + }, + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Set to get the number of records after this cursor.", + "schema": { + "type": "string" + } } ], "responses": { @@ -4026,7 +4051,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTicketOutput" + "$ref": "#/components/schemas/UnifiedTagOutput" } } } @@ -4037,7 +4062,7 @@ } }, "tags": [ - "ticketing/tickets" + "ticketing/tags" ], "security": [ { @@ -4046,16 +4071,17 @@ ] } }, - "/ticketing/tickets/batch": { - "post": { - "operationId": "addTickets", - "summary": "Add a batch of Tickets", + "/ticketing/tags/{id}": { + "get": { + "operationId": "getTag", + "summary": "Retrieve a Tag", + "description": "Retrieve a tag from any connected Ticketing software", "parameters": [ { - "name": "x-connection-token", + "name": "id", "required": true, - "in": "header", - "description": "The connection token", + "in": "path", + "description": "id of the tag you want to retrieve.", "schema": { "type": "string" } @@ -4070,19 +4096,6 @@ } } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UnifiedTicketInput" - } - } - } - } - }, "responses": { "200": { "description": "", @@ -4096,7 +4109,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedTicketOutput" + "$ref": "#/components/schemas/UnifiedTagOutput" } } } @@ -4104,23 +4117,10 @@ } } } - }, - "201": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UnifiedTicketOutput" - } - } - } - } } }, "tags": [ - "ticketing/tickets" + "ticketing/tags" ], "security": [ { @@ -4129,10 +4129,10 @@ ] } }, - "/ticketing/users": { + "/ticketing/teams": { "get": { - "operationId": "getUsers", - "summary": "List a batch of Users", + "operationId": "getTeams", + "summary": "List a batch of Teams", "parameters": [ { "name": "x-connection-token", @@ -4185,7 +4185,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedUserOutput" + "$ref": "#/components/schemas/UnifiedTeamOutput" } } } @@ -4196,7 +4196,7 @@ } }, "tags": [ - "ticketing/users" + "ticketing/teams" ], "security": [ { @@ -4205,17 +4205,17 @@ ] } }, - "/ticketing/users/{id}": { + "/ticketing/teams/{id}": { "get": { - "operationId": "getUser", - "summary": "Retrieve a User", - "description": "Retrieve a user from any connected Ticketing software", + "operationId": "getTeam", + "summary": "Retrieve a Team", + "description": "Retrieve a team from any connected Ticketing software", "parameters": [ { "name": "id", "required": true, "in": "path", - "description": "id of the user you want to retrieve.", + "description": "id of the team you want to retrieve.", "schema": { "type": "string" } @@ -4243,7 +4243,7 @@ { "properties": { "data": { - "$ref": "#/components/schemas/UnifiedUserOutput" + "$ref": "#/components/schemas/UnifiedTeamOutput" } } } @@ -4254,7 +4254,7 @@ } }, "tags": [ - "ticketing/users" + "ticketing/teams" ], "security": [ { @@ -5642,35 +5642,387 @@ "statusCode" ] }, - "Email": { + "UnifiedCommentInput": { "type": "object", "properties": { - "email_address": { + "body": { "type": "string", - "description": "The email address" + "description": "The body of the comment" }, - "email_address_type": { + "html_body": { "type": "string", - "description": "The email address type. Authorized values are either PERSONAL or WORK." + "description": "The html body of the comment" }, - "owner_type": { - "type": "string", - "description": "The owner type of an email" - } - }, - "required": [ - "email_address", - "email_address_type" - ] - }, - "Address": { - "type": "object", - "properties": { - "street_1": { - "type": "string", - "description": "The street" + "is_private": { + "type": "boolean", + "description": "The public status of the comment" }, - "street_2": { + "creator_type": { + "type": "string", + "description": "The creator type of the comment. Authorized values are either USER or CONTACT" + }, + "ticket_id": { + "type": "string", + "description": "The uuid of the ticket the comment is tied to" + }, + "contact_id": { + "type": "string", + "description": "The uuid of the contact which the comment belongs to (if no user_id specified)" + }, + "user_id": { + "type": "string", + "description": "The uuid of the user which the comment belongs to (if no contact_id specified)" + }, + "attachments": { + "description": "The attachements uuids tied to the comment", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "body" + ] + }, + "UnifiedTicketOutput": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the ticket" + }, + "status": { + "type": "string", + "description": "The status of the ticket. Authorized values are OPEN or CLOSED." + }, + "description": { + "type": "string", + "description": "The description of the ticket" + }, + "due_date": { + "format": "date-time", + "type": "string", + "description": "The date the ticket is due" + }, + "type": { + "type": "string", + "description": "The type of the ticket. Authorized values are PROBLEM, QUESTION, or TASK" + }, + "parent_ticket": { + "type": "string", + "description": "The uuid of the parent ticket" + }, + "project_id": { + "type": "string", + "description": "The uuid of the collection (project) the ticket belongs to" + }, + "tags": { + "description": "The tags names of the ticket", + "type": "array", + "items": { + "type": "string" + } + }, + "completed_at": { + "format": "date-time", + "type": "string", + "description": "The date the ticket has been completed" + }, + "priority": { + "type": "string", + "description": "The priority of the ticket. Authorized values are HIGH, MEDIUM or LOW." + }, + "assigned_to": { + "description": "The users uuids the ticket is assigned to", + "type": "array", + "items": { + "type": "string" + } + }, + "comment": { + "description": "The comment of the ticket", + "allOf": [ + { + "$ref": "#/components/schemas/UnifiedCommentInput" + } + ] + }, + "account_id": { + "type": "string", + "description": "The uuid of the account which the ticket belongs to" + }, + "contact_id": { + "type": "string", + "description": "The uuid of the contact which the ticket belongs to" + }, + "field_mappings": { + "type": "object", + "properties": {} + }, + "id": { + "type": "string", + "description": "The uuid of the ticket" + }, + "remote_id": { + "type": "string", + "description": "The id of the ticket in the context of the 3rd Party" + }, + "remote_data": { + "type": "object", + "properties": {} + } + }, + "required": [ + "name", + "description", + "field_mappings", + "remote_data" + ] + }, + "UnifiedTicketInput": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the ticket" + }, + "status": { + "type": "string", + "description": "The status of the ticket. Authorized values are OPEN or CLOSED." + }, + "description": { + "type": "string", + "description": "The description of the ticket" + }, + "due_date": { + "format": "date-time", + "type": "string", + "description": "The date the ticket is due" + }, + "type": { + "type": "string", + "description": "The type of the ticket. Authorized values are PROBLEM, QUESTION, or TASK" + }, + "parent_ticket": { + "type": "string", + "description": "The uuid of the parent ticket" + }, + "project_id": { + "type": "string", + "description": "The uuid of the collection (project) the ticket belongs to" + }, + "tags": { + "description": "The tags names of the ticket", + "type": "array", + "items": { + "type": "string" + } + }, + "completed_at": { + "format": "date-time", + "type": "string", + "description": "The date the ticket has been completed" + }, + "priority": { + "type": "string", + "description": "The priority of the ticket. Authorized values are HIGH, MEDIUM or LOW." + }, + "assigned_to": { + "description": "The users uuids the ticket is assigned to", + "type": "array", + "items": { + "type": "string" + } + }, + "comment": { + "description": "The comment of the ticket", + "allOf": [ + { + "$ref": "#/components/schemas/UnifiedCommentInput" + } + ] + }, + "account_id": { + "type": "string", + "description": "The uuid of the account which the ticket belongs to" + }, + "contact_id": { + "type": "string", + "description": "The uuid of the contact which the ticket belongs to" + }, + "field_mappings": { + "type": "object", + "properties": {} + } + }, + "required": [ + "name", + "description", + "field_mappings" + ] + }, + "UnifiedUserOutput": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the user" + }, + "email": { + "type": "string", + "description": "The email of the user" + }, + "field_mappings": { + "type": "object", + "properties": {} + }, + "id": { + "type": "string", + "description": "The uuid of the user" + }, + "remote_id": { + "type": "string", + "description": "The id of the user in the context of the Crm 3rd Party" + }, + "remote_data": { + "type": "object", + "properties": {} + } + }, + "required": [ + "name", + "email", + "field_mappings", + "remote_data" + ] + }, + "UnifiedAccountOutput": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the account" + }, + "domains": { + "description": "The domains of the account", + "type": "array", + "items": { + "type": "string" + } + }, + "field_mappings": { + "type": "object", + "properties": {} + }, + "id": { + "type": "string", + "description": "The uuid of the account" + }, + "remote_id": { + "type": "string", + "description": "The id of the account in the context of the 3rd Party" + }, + "remote_data": { + "type": "object", + "properties": {} + } + }, + "required": [ + "name", + "field_mappings", + "remote_data" + ] + }, + "UnifiedContactOutput": { + "type": "object", + "properties": { + "first_name": { + "type": "string", + "description": "The first name of the contact" + }, + "last_name": { + "type": "string", + "description": "The last name of the contact" + }, + "email_addresses": { + "description": "The email addresses of the contact", + "type": "array", + "items": { + "$ref": "#/components/schemas/Email" + } + }, + "phone_numbers": { + "description": "The phone numbers of the contact", + "type": "array", + "items": { + "$ref": "#/components/schemas/Phone" + } + }, + "addresses": { + "description": "The addresses of the contact", + "type": "array", + "items": { + "$ref": "#/components/schemas/Address" + } + }, + "user_id": { + "type": "string", + "description": "The uuid of the user who owns the contact" + }, + "field_mappings": { + "type": "object", + "properties": {} + }, + "id": { + "type": "string", + "description": "The uuid of the contact" + }, + "remote_id": { + "type": "string", + "description": "The id of the contact in the context of the Crm 3rd Party" + }, + "remote_data": { + "type": "object", + "properties": {} + } + }, + "required": [ + "first_name", + "last_name", + "field_mappings", + "remote_data" + ] + }, + "Email": { + "type": "object", + "properties": { + "email_address": { + "type": "string", + "description": "The email address" + }, + "email_address_type": { + "type": "string", + "description": "The email address type. Authorized values are either PERSONAL or WORK." + }, + "owner_type": { + "type": "string", + "description": "The owner type of an email" + } + }, + "required": [ + "email_address", + "email_address_type" + ] + }, + "Address": { + "type": "object", + "properties": { + "street_1": { + "type": "string", + "description": "The street" + }, + "street_2": { "type": "string", "description": "More information about the street " }, @@ -5844,49 +6196,6 @@ "field_mappings" ] }, - "UnifiedContactOutput": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the contact" - }, - "email_address": { - "type": "string", - "description": "The email address of the contact" - }, - "phone_number": { - "type": "string", - "description": "The phone number of the contact" - }, - "details": { - "type": "string", - "description": "The details of the contact" - }, - "field_mappings": { - "type": "object", - "properties": {} - }, - "id": { - "type": "string", - "description": "The uuid of the contact" - }, - "remote_id": { - "type": "string", - "description": "The id of the contact in the context of the 3rd Party" - }, - "remote_data": { - "type": "object", - "properties": {} - } - }, - "required": [ - "name", - "email_address", - "field_mappings", - "remote_data" - ] - }, "UnifiedContactInput": { "type": "object", "properties": { @@ -6333,120 +6642,37 @@ "description": "The status of the task. Authorized values are PENDING, COMPLETED." }, "due_date": { - "format": "date-time", - "type": "string", - "description": "The due date of the task" - }, - "finished_date": { - "format": "date-time", - "type": "string", - "description": "The finished date of the task" - }, - "user_id": { - "type": "string", - "description": "The uuid of the user tied to the task" - }, - "company_id": { - "type": "string", - "description": "The uuid fo the company tied to the task" - }, - "deal_id": { - "type": "string", - "description": "The uuid of the deal tied to the task" - }, - "field_mappings": { - "type": "object", - "properties": {} - } - }, - "required": [ - "subject", - "content", - "status", - "field_mappings" - ] - }, - "UnifiedUserOutput": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the user" - }, - "email_address": { - "type": "string", - "description": "The email address of the user" - }, - "teams": { - "description": "The teams whose the user is part of", - "type": "array", - "items": { - "type": "string" - } - }, - "account_id": { - "type": "string", - "description": "The account or organization the user is part of" - }, - "field_mappings": { - "type": "object", - "properties": {} - }, - "id": { - "type": "string", - "description": "The uuid of the user" - }, - "remote_id": { - "type": "string", - "description": "The id of the user in the context of the 3rd Party" - }, - "remote_data": { - "type": "object", - "properties": {} - } - }, - "required": [ - "name", - "email_address", - "field_mappings", - "remote_data" - ] - }, - "UnifiedAccountOutput": { - "type": "object", - "properties": { - "name": { + "format": "date-time", "type": "string", - "description": "The name of the account" + "description": "The due date of the task" }, - "domains": { - "description": "The domains of the account", - "type": "array", - "items": { - "type": "string" - } + "finished_date": { + "format": "date-time", + "type": "string", + "description": "The finished date of the task" }, - "field_mappings": { - "type": "object", - "properties": {} + "user_id": { + "type": "string", + "description": "The uuid of the user tied to the task" }, - "id": { + "company_id": { "type": "string", - "description": "The uuid of the account" + "description": "The uuid fo the company tied to the task" }, - "remote_id": { + "deal_id": { "type": "string", - "description": "The id of the account in the context of the 3rd Party" + "description": "The uuid of the deal tied to the task" }, - "remote_data": { + "field_mappings": { "type": "object", "properties": {} } }, "required": [ - "name", - "field_mappings", - "remote_data" + "subject", + "content", + "status", + "field_mappings" ] }, "UnifiedCollectionOutput": { @@ -6578,49 +6804,6 @@ "remote_data" ] }, - "UnifiedCommentInput": { - "type": "object", - "properties": { - "body": { - "type": "string", - "description": "The body of the comment" - }, - "html_body": { - "type": "string", - "description": "The html body of the comment" - }, - "is_private": { - "type": "boolean", - "description": "The public status of the comment" - }, - "creator_type": { - "type": "string", - "description": "The creator type of the comment. Authorized values are either USER or CONTACT" - }, - "ticket_id": { - "type": "string", - "description": "The uuid of the ticket the comment is tied to" - }, - "contact_id": { - "type": "string", - "description": "The uuid of the contact which the comment belongs to (if no user_id specified)" - }, - "user_id": { - "type": "string", - "description": "The uuid of the user which the comment belongs to (if no contact_id specified)" - }, - "attachments": { - "description": "The attachements uuids tied to the comment", - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "body" - ] - }, "UnifiedTagOutput": { "type": "object", "properties": { @@ -6685,183 +6868,6 @@ "remote_data" ] }, - "UnifiedTicketOutput": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the ticket" - }, - "status": { - "type": "string", - "description": "The status of the ticket. Authorized values are OPEN or CLOSED." - }, - "description": { - "type": "string", - "description": "The description of the ticket" - }, - "due_date": { - "format": "date-time", - "type": "string", - "description": "The date the ticket is due" - }, - "type": { - "type": "string", - "description": "The type of the ticket. Authorized values are PROBLEM, QUESTION, or TASK" - }, - "parent_ticket": { - "type": "string", - "description": "The uuid of the parent ticket" - }, - "project_id": { - "type": "string", - "description": "The uuid of the collection (project) the ticket belongs to" - }, - "tags": { - "description": "The tags names of the ticket", - "type": "array", - "items": { - "type": "string" - } - }, - "completed_at": { - "format": "date-time", - "type": "string", - "description": "The date the ticket has been completed" - }, - "priority": { - "type": "string", - "description": "The priority of the ticket. Authorized values are HIGH, MEDIUM or LOW." - }, - "assigned_to": { - "description": "The users uuids the ticket is assigned to", - "type": "array", - "items": { - "type": "string" - } - }, - "comment": { - "description": "The comment of the ticket", - "allOf": [ - { - "$ref": "#/components/schemas/UnifiedCommentInput" - } - ] - }, - "account_id": { - "type": "string", - "description": "The uuid of the account which the ticket belongs to" - }, - "contact_id": { - "type": "string", - "description": "The uuid of the contact which the ticket belongs to" - }, - "field_mappings": { - "type": "object", - "properties": {} - }, - "id": { - "type": "string", - "description": "The uuid of the ticket" - }, - "remote_id": { - "type": "string", - "description": "The id of the ticket in the context of the 3rd Party" - }, - "remote_data": { - "type": "object", - "properties": {} - } - }, - "required": [ - "name", - "description", - "field_mappings", - "remote_data" - ] - }, - "UnifiedTicketInput": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the ticket" - }, - "status": { - "type": "string", - "description": "The status of the ticket. Authorized values are OPEN or CLOSED." - }, - "description": { - "type": "string", - "description": "The description of the ticket" - }, - "due_date": { - "format": "date-time", - "type": "string", - "description": "The date the ticket is due" - }, - "type": { - "type": "string", - "description": "The type of the ticket. Authorized values are PROBLEM, QUESTION, or TASK" - }, - "parent_ticket": { - "type": "string", - "description": "The uuid of the parent ticket" - }, - "project_id": { - "type": "string", - "description": "The uuid of the collection (project) the ticket belongs to" - }, - "tags": { - "description": "The tags names of the ticket", - "type": "array", - "items": { - "type": "string" - } - }, - "completed_at": { - "format": "date-time", - "type": "string", - "description": "The date the ticket has been completed" - }, - "priority": { - "type": "string", - "description": "The priority of the ticket. Authorized values are HIGH, MEDIUM or LOW." - }, - "assigned_to": { - "description": "The users uuids the ticket is assigned to", - "type": "array", - "items": { - "type": "string" - } - }, - "comment": { - "description": "The comment of the ticket", - "allOf": [ - { - "$ref": "#/components/schemas/UnifiedCommentInput" - } - ] - }, - "account_id": { - "type": "string", - "description": "The uuid of the account which the ticket belongs to" - }, - "contact_id": { - "type": "string", - "description": "The uuid of the contact which the ticket belongs to" - }, - "field_mappings": { - "type": "object", - "properties": {} - } - }, - "required": [ - "name", - "description", - "field_mappings" - ] - }, "CreateLinkedUserDto": { "type": "object", "properties": { From 196e08e35aad8cc21ea12f234f13ea672ad937c0 Mon Sep 17 00:00:00 2001 From: nael Date: Sat, 15 Jun 2024 12:51:43 +0200 Subject: [PATCH 3/3] :bug: Fix connector script --- packages/api/scripts/connectorUpdate.js | 75 +++++++------------ packages/api/scripts/init.sql | 4 +- packages/api/scripts/seed.sql | 8 +- .../types/original/original.ticketing.ts | 24 ++---- .../ticketing/account/types/mappingsTypes.ts | 1 - packages/shared/src/connectors/enum.ts | 4 +- packages/shared/src/connectors/index.ts | 2 +- 7 files changed, 43 insertions(+), 75 deletions(-) diff --git a/packages/api/scripts/connectorUpdate.js b/packages/api/scripts/connectorUpdate.js index 06cee31ce..f993135ad 100755 --- a/packages/api/scripts/connectorUpdate.js +++ b/packages/api/scripts/connectorUpdate.js @@ -3,8 +3,11 @@ THIS SCRIPT UPDATES ALL DEPENDENCIES WHEN A NEW SERVICE 3RD PARTY IS ADDED TO THE CODEBASE AFTER ADDING THE NEW CONNECTOR, CONTRIBUTOR JUST HAS TO RUN (EXAMPLE FOR CRM VERTICAL AND CONTACT COMMON OBJECT) - pnpm run validate-connectors --vertical="crm" --objectType="contact" + 1. Build: + docker build -t validate_connectors -f ./packages/api/Dockerfile.validate-connectors . + 2. Run: + docker run -v $(pwd):/app/ -e VERTICAL=crm -e OBJECT_TYPE=contact validate_connectors */ import * as fs from 'fs'; @@ -79,62 +82,34 @@ function updateTargetFile(file, importStatements, serviceNames, objectType) { objectType = objectType.charAt(0).toUpperCase() + objectType.slice(1); if (importStatements.length > 0) { - // Append the import statements fileContent = importStatements.join('\n') + '\n\n' + fileContent; } - // Create updates for OriginalObjectTypeInput and OriginalObjectTypeOutput serviceNames.forEach((serviceName) => { const typeName = - serviceName.charAt(0).toUpperCase() + serviceName.slice(1) + objectType; // Assuming naming convention + serviceName.charAt(0).toUpperCase() + serviceName.slice(1) + objectType; const inputTypeName = `${typeName}Input`; const outputTypeName = `${typeName}Output`; - // Update OriginalObjectTypeInput - - // checking whether OriginalObjectTypeInput assigns null - const inputNullRegex = new RegExp( - `(export type Original${objectType}Input = null)`, - ); - if (inputNullRegex.test(fileContent)) { - fileContent = fileContent.replace( - inputNullRegex, - `export type Original${objectType}Input =`, - ); - } - const inputRegex = new RegExp(`(export type Original${objectType}Input =)`); - if (inputRegex.test(fileContent)) { - fileContent = fileContent.replace(inputRegex, `$1\n | ${inputTypeName}`); - } else { - // If the type doesn't exist, add it - fileContent += `\nexport type Original${objectType}Input =\n | ${inputTypeName};\n`; - } - - // Update OriginalObjectTypeOutput - - // checking whether OriginalObjectTypeInput assigns null - const outputNullRegex = new RegExp( - `(export type Original${objectType}Input = null)`, - ); - if (outputNullRegex.test(fileContent)) { - fileContent = fileContent.replace( - outputNullRegex, - `export type Original${objectType}Output =`, - ); + // Function to append type with correct pipe placement + function appendType(baseType, newType) { + const regex = new RegExp(`(export type ${baseType} =)([^;]*)`); + if (regex.test(fileContent)) { + fileContent = fileContent.replace(regex, (match, p1, p2) => { + if (p2.trim().endsWith('|')) { + return `${p1}${p2} ${newType}`; + } else { + return `${p1}${p2} | ${newType}`; + } + }); + } else { + fileContent += `\nexport type ${baseType} = ${newType};\n`; + } } - const outputRegex = new RegExp( - `(export type Original${objectType}Output =)`, - ); - if (outputRegex.test(fileContent)) { - fileContent = fileContent.replace( - outputRegex, - `$1\n | ${outputTypeName}`, - ); - } else { - // If the type doesn't exist, add it - fileContent += `\nexport type Original${objectType}Output =\n | ${outputTypeName};\n`; - } + // Update inputs and outputs + appendType(`Original${objectType}Input`, inputTypeName); + appendType(`Original${objectType}Output`, outputTypeName); }); fs.writeFileSync(file, fileContent); @@ -369,7 +344,8 @@ function updateInitSQLFile(initSQLFile, newServiceDirs, vertical) { // New function to update seed.sql function updateSeedSQLFile(seedSQLFile, newServiceDirs, vertical) { let fileContent = fs.readFileSync(seedSQLFile, 'utf8'); - + console.log('new providers are ' + newServiceDirs); + console.log('new vertical is ' + vertical); // Regex to find the INSERT statement for connector_sets const regex = /INSERT INTO connector_sets \(([^)]+)\) VALUES/g; let match; @@ -387,6 +363,7 @@ function updateSeedSQLFile(seedSQLFile, newServiceDirs, vertical) { let newColumns = newServiceDirs.map( (serviceName) => `${vertical.toLowerCase()}_${serviceName.toLowerCase()}`, ); + console.log(newColumns); // Filter out existing new columns to avoid duplication newColumns = newColumns.filter((nc) => !columns.includes(nc)); @@ -409,6 +386,8 @@ function updateSeedSQLFile(seedSQLFile, newServiceDirs, vertical) { }); } // Write the modified content back to the file + console.log(fileContent); + fs.writeFileSync(seedSQLFile, fileContent); console.log('Seed SQL file has been updated successfully.'); } diff --git a/packages/api/scripts/init.sql b/packages/api/scripts/init.sql index 30c8b1cc8..05ebc6a61 100644 --- a/packages/api/scripts/init.sql +++ b/packages/api/scripts/init.sql @@ -423,10 +423,10 @@ CREATE TABLE connector_sets tcg_gorgias boolean NOT NULL, tcg_gitlab boolean NOT NULL, tcg_front boolean NOT NULL, - CONSTRAINT PK_project_connector PRIMARY KEY ( id_connector_set ) +CONSTRAINT PK_project_connector PRIMARY KEY ( id_connector_set ) ); - + diff --git a/packages/api/scripts/seed.sql b/packages/api/scripts/seed.sql index 620985342..60b6fc09e 100644 --- a/packages/api/scripts/seed.sql +++ b/packages/api/scripts/seed.sql @@ -1,5 +1,5 @@ INSERT INTO users (id_user, identification_strategy, email, password_hash, first_name, last_name) VALUES -('0ce39030-2901-4c56-8db0-5e326182ec6b', 'b2c','local@panora.dev', '$2b$10$Y7Q8TWGyGuc5ecdIASbBsuXMo3q/Rs3/cnY.mLZP4tUgfGUOCUBlG', 'local', 'Panora'); +('0ce39030-2901-4c56-8db0-5e326182ec6b', 'b2c','local@panora.dev', '$2b$10$Y7Q8TWGyGuc5ecdIASbBsuXMo3q/Rs3/cnY.mLZP4tUgfGUOCUBlG', 'local', 'Panora', TRUE, TRUE); INSERT INTO connector_sets (id_connector_set, crm_hubspot, crm_zoho, crm_pipedrive, crm_attio, crm_zendesk, crm_close, tcg_zendesk, tcg_gorgias, tcg_front, tcg_jira, tcg_gitlab) VALUES ('1709da40-17f7-4d3a-93a0-96dc5da6ddd7', TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE), @@ -7,6 +7,6 @@ INSERT INTO connector_sets (id_connector_set, crm_hubspot, crm_zoho, crm_pipedri ('aed0f856-f802-4a79-8640-66d441581a99', TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE); INSERT INTO projects (id_project, name, sync_mode, id_user, id_connector_set) VALUES - ('1e468c15-aa57-4448-aa2b-7fed640d1e3d', 'Project 1', 'pool', '0ce39030-2901-4c56-8db0-5e326182ec6b', '1709da40-17f7-4d3a-93a0-96dc5da6ddd7'), - ('4c641a21-a7f8-4ffe-b7e8-e7d32db87557', 'Project 2', 'pool', '0ce39030-2901-4c56-8db0-5e326182ec6b', '852dfff8-ab63-4530-ae49-e4b2924407f8'), - ('2b198012-c79c-4bb6-971e-9635830e8c15', 'Project 3', 'pool', '0ce39030-2901-4c56-8db0-5e326182ec6b', 'aed0f856-f802-4a79-8640-66d441581a99'); + ('1e468c15-aa57-4448-aa2b-7fed640d1e3d', 'Project 1', 'pool', '0ce39030-2901-4c56-8db0-5e326182ec6b', '1709da40-17f7-4d3a-93a0-96dc5da6ddd7', TRUE, TRUE), + ('4c641a21-a7f8-4ffe-b7e8-e7d32db87557', 'Project 2', 'pool', '0ce39030-2901-4c56-8db0-5e326182ec6b', '852dfff8-ab63-4530-ae49-e4b2924407f8', TRUE, TRUE), + ('2b198012-c79c-4bb6-971e-9635830e8c15', 'Project 3', 'pool', '0ce39030-2901-4c56-8db0-5e326182ec6b', 'aed0f856-f802-4a79-8640-66d441581a99', TRUE, TRUE); diff --git a/packages/api/src/@core/utils/types/original/original.ticketing.ts b/packages/api/src/@core/utils/types/original/original.ticketing.ts index aa905750f..8410fe32f 100644 --- a/packages/api/src/@core/utils/types/original/original.ticketing.ts +++ b/packages/api/src/@core/utils/types/original/original.ticketing.ts @@ -1,5 +1,3 @@ - - import { FrontAccountInput, FrontAccountOutput, @@ -84,7 +82,10 @@ import { JiraTagInput, JiraTagOutput, } from '@ticketing/tag/services/jira/types'; -import { JiraCollectionOutput, JiraCollectionInput } from '@ticketing/collection/services/jira/types'; +import { + JiraCollectionOutput, + JiraCollectionInput, +} from '@ticketing/collection/services/jira/types'; import { ZendeskTicketInput, ZendeskTicketOutput, @@ -123,8 +124,8 @@ import { } from '@ticketing/ticket/services/gitlab/types'; import { GitlabCommentInput, - GitlabCommentOutput -} from '@ticketing/comment/services/gitlab/types' + GitlabCommentOutput, +} from '@ticketing/comment/services/gitlab/types'; /* INPUT */ @@ -155,9 +156,7 @@ export type OriginalUserInput = | JiraUserInput; //| JiraServiceMgmtUserInput; /* account */ -export type OriginalAccountInput = - | ZendeskAccountInput - | FrontAccountInput; +export type OriginalAccountInput = ZendeskAccountInput | FrontAccountInput; /* contact */ export type OriginalContactInput = | ZendeskContactInput @@ -221,9 +220,7 @@ export type OriginalUserOutput = | GorgiasUserOutput | JiraUserOutput; /* account */ -export type OriginalAccountOutput = - | ZendeskAccountOutput - | FrontAccountOutput; +export type OriginalAccountOutput = ZendeskAccountOutput | FrontAccountOutput; /* contact */ export type OriginalContactOutput = | ZendeskContactOutput @@ -257,7 +254,6 @@ export type OriginalCollectionOutput = | JiraCollectionOutput | GitlabCollectionOutput; - export type TicketingObjectOutput = | OriginalTicketOutput | OriginalCommentOutput @@ -268,7 +264,3 @@ export type TicketingObjectOutput = | OriginalContactOutput | OriginalAccountOutput | OriginalCollectionOutput; - - - - diff --git a/packages/api/src/ticketing/account/types/mappingsTypes.ts b/packages/api/src/ticketing/account/types/mappingsTypes.ts index 1f7179213..0282ed019 100644 --- a/packages/api/src/ticketing/account/types/mappingsTypes.ts +++ b/packages/api/src/ticketing/account/types/mappingsTypes.ts @@ -3,7 +3,6 @@ import { ZendeskAccountMapper } from '../services/zendesk/mappers'; const zendeskAccountMapper = new ZendeskAccountMapper(); const frontAccountMapper = new FrontAccountMapper(); - export const accountUnificationMapping = { zendesk: { unify: zendeskAccountMapper.unify.bind(zendeskAccountMapper), diff --git a/packages/shared/src/connectors/enum.ts b/packages/shared/src/connectors/enum.ts index 7c3a770e9..ce0ef4aaf 100644 --- a/packages/shared/src/connectors/enum.ts +++ b/packages/shared/src/connectors/enum.ts @@ -10,11 +10,9 @@ export enum CrmConnectors { export enum TicketingConnectors { ZENDESK = 'zendesk', FRONT = 'front', - GITHUB = 'github', JIRA = 'jira', GORGIAS = 'gorgias', - GITLAB = 'gitlab', - HUBSPOT = 'hubspot', + GITLAB = 'gitlab' } export enum AccountingConnectors { diff --git a/packages/shared/src/connectors/index.ts b/packages/shared/src/connectors/index.ts index 8de1dda5c..00da95934 100644 --- a/packages/shared/src/connectors/index.ts +++ b/packages/shared/src/connectors/index.ts @@ -2,6 +2,6 @@ export const CRM_PROVIDERS = ['zoho', 'zendesk', 'hubspot', 'pipedrive', 'attio' export const HRIS_PROVIDERS = ['']; export const ATS_PROVIDERS = ['']; export const ACCOUNTING_PROVIDERS = ['']; -export const TICKETING_PROVIDERS = ['zendesk', 'front', 'github', 'jira', 'gorgias', 'gitlab', 'hubspot']; +export const TICKETING_PROVIDERS = ['zendesk', 'front', 'jira', 'gorgias', 'gitlab']; export const MARKETINGAUTOMATION_PROVIDERS = ['']; export const FILESTORAGE_PROVIDERS = [''];