diff --git a/packages/api/scripts/commonObject.sh b/packages/api/scripts/commonObject.sh index 29e19d00d..fc52b578f 100755 --- a/packages/api/scripts/commonObject.sh +++ b/packages/api/scripts/commonObject.sh @@ -323,7 +323,7 @@ export class ${ObjectCap}Controller { @ApiHeader({ name: 'integrationId', required: true }) @ApiHeader({ name: 'linkedUserId', required: true }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: @@ -334,7 +334,7 @@ export class ${ObjectCap}Controller { get${ObjectCap}s( @Headers('integrationId') integrationId: string, @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.${objectType}Service.get${ObjectCap}s( integrationId, @@ -355,7 +355,7 @@ export class ${ObjectCap}Controller { description: 'id of the ${objectType} you want to retrieve.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: @@ -365,7 +365,7 @@ export class ${ObjectCap}Controller { @Get(':id') get${ObjectCap}( @Param('id') id: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.${objectType}Service.get${ObjectCap}(id, remote_data); } @@ -388,7 +388,7 @@ export class ${ObjectCap}Controller { example: 'b008e199-eda9-4629-bd41-a01b6195864a', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: @@ -401,7 +401,7 @@ export class ${ObjectCap}Controller { @Body() unified${ObjectCap}Data: Unified${ObjectCap}Input, @Headers('integrationId') integrationId: string, @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.${objectType}Service.add${ObjectCap}( unified${ObjectCap}Data, @@ -418,7 +418,7 @@ export class ${ObjectCap}Controller { @ApiHeader({ name: 'integrationId', required: true }) @ApiHeader({ name: 'linkedUserId', required: true }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: @@ -431,7 +431,7 @@ export class ${ObjectCap}Controller { @Body() unfied${ObjectCap}Data: Unified${ObjectCap}Input[], @Headers('integrationId') integrationId: string, @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.${objectType}Service.batchAdd${ObjectCap}s( unfied${ObjectCap}Data, diff --git a/packages/api/src/@core/connections/@utils/index.ts b/packages/api/src/@core/connections/@utils/index.ts new file mode 100644 index 000000000..12e63b3d6 --- /dev/null +++ b/packages/api/src/@core/connections/@utils/index.ts @@ -0,0 +1,35 @@ +import { PrismaClient } from '@prisma/client'; + +export type ConnectionMetadata = { + linkedUserId: string; + remoteSource: string; +}; + +export class ConnectionUtils { + private readonly prisma: PrismaClient; + + constructor() { + this.prisma = new PrismaClient(); + } + + async getConnectionMetadataFromConnectionToken( + token: string, + ): Promise { + try { + if (!token) + throw new Error('token provided for connection token is invalid'); + const res = await this.prisma.connections.findFirst({ + where: { + connection_token: token, + }, + }); + if (!res) throw new Error(`connection not found for token ${token}`); + return { + linkedUserId: res.id_linked_user, + remoteSource: res.provider_slug, + }; + } catch (error) { + throw new Error(error); + } + } +} diff --git a/packages/api/src/@core/connections/connections.controller.ts b/packages/api/src/@core/connections/connections.controller.ts index bb04720ed..07cdd86f9 100644 --- a/packages/api/src/@core/connections/connections.controller.ts +++ b/packages/api/src/@core/connections/connections.controller.ts @@ -93,6 +93,11 @@ export class ConnectionsController { @ApiResponse({ status: 200 }) @Get() async getConnections() { - return await this.prisma.connections.findMany(); + return await this.prisma.connections.findMany({ + select: { + access_token: false, + refresh_token: false, + }, + }); } } diff --git a/packages/api/src/@core/connections/crm/services/crm.connection.service.ts b/packages/api/src/@core/connections/crm/services/crm.connection.service.ts index 4259b7769..7800c7594 100644 --- a/packages/api/src/@core/connections/crm/services/crm.connection.service.ts +++ b/packages/api/src/@core/connections/crm/services/crm.connection.service.ts @@ -41,19 +41,6 @@ export class CrmConnectionsService { zohoLocation?: string, ) { try { - const job_resp_create = await this.prisma.events.create({ - data: { - id_event: uuidv4(), - status: 'initialized', - type: 'connection.created', - method: 'GET', - url: '/oauth/callback', - provider: providerName.toLowerCase(), - direction: '0', - timestamp: new Date(), - id_linked_user: linkedUserId, - }, - }); if (!code) { throw new NotFoundError(`no ${providerName} code found, found ${code}`); } @@ -72,19 +59,24 @@ export class CrmConnectionsService { }; const data: Connection = await service.handleCallback(callbackOpts); - await this.prisma.events.update({ - where: { - id_event: job_resp_create.id_event, - }, + const event = await this.prisma.events.create({ data: { + id_event: uuidv4(), status: 'success', + type: 'connection.created', + method: 'GET', + url: '/oauth/callback', + provider: providerName.toLowerCase(), + direction: '0', + timestamp: new Date(), + id_linked_user: linkedUserId, }, }); await this.webhook.handleWebhook( data, 'connection.created', projectId, - job_resp_create.id_event, + event.id_event, ); } catch (error) { handleServiceError(error, this.logger); diff --git a/packages/api/src/@core/connections/crm/services/hubspot/hubspot.service.ts b/packages/api/src/@core/connections/crm/services/hubspot/hubspot.service.ts index 393bd5ad5..05fbd3283 100644 --- a/packages/api/src/@core/connections/crm/services/hubspot/hubspot.service.ts +++ b/packages/api/src/@core/connections/crm/services/hubspot/hubspot.service.ts @@ -59,6 +59,8 @@ export class HubspotConnectionService implements ICrmConnectionService { const data: HubspotOAuthResponse = res.data; // save tokens for this customer inside our db let db_res; + const connection_token = uuidv4(); + if (isNotUnique) { // Update existing connection db_res = await this.prisma.connections.update({ @@ -80,6 +82,7 @@ export class HubspotConnectionService implements ICrmConnectionService { db_res = await this.prisma.connections.create({ data: { id_connection: uuidv4(), + connection_token: connection_token, provider_slug: 'hubspot', token_type: 'oauth', access_token: this.cryptoService.encrypt(data.access_token), diff --git a/packages/api/src/@core/connections/crm/services/pipedrive/pipedrive.service.ts b/packages/api/src/@core/connections/crm/services/pipedrive/pipedrive.service.ts index 47dde21e9..ec8af5f79 100644 --- a/packages/api/src/@core/connections/crm/services/pipedrive/pipedrive.service.ts +++ b/packages/api/src/@core/connections/crm/services/pipedrive/pipedrive.service.ts @@ -59,6 +59,7 @@ export class PipedriveConnectionService implements ICrmConnectionService { const data: PipeDriveOAuthResponse = res.data; this.logger.log('OAuth credentials : pipedrive '); let db_res; + const connection_token = uuidv4(); if (isNotUnique) { db_res = await this.prisma.connections.update({ @@ -79,6 +80,7 @@ export class PipedriveConnectionService implements ICrmConnectionService { db_res = await this.prisma.connections.create({ data: { id_connection: uuidv4(), + connection_token: connection_token, provider_slug: 'pipedrive', token_type: 'oauth', access_token: this.cryptoService.encrypt(data.access_token), diff --git a/packages/api/src/@core/connections/crm/services/zendesk/zendesk.service.ts b/packages/api/src/@core/connections/crm/services/zendesk/zendesk.service.ts index ce2f78324..9926c8796 100644 --- a/packages/api/src/@core/connections/crm/services/zendesk/zendesk.service.ts +++ b/packages/api/src/@core/connections/crm/services/zendesk/zendesk.service.ts @@ -59,6 +59,7 @@ export class ZendeskConnectionService implements ICrmConnectionService { this.logger.log('OAuth credentials : zendesk ' + JSON.stringify(data)); let db_res; + const connection_token = uuidv4(); if (isNotUnique) { db_res = await this.prisma.connections.update({ @@ -81,6 +82,7 @@ export class ZendeskConnectionService implements ICrmConnectionService { db_res = await this.prisma.connections.create({ data: { id_connection: uuidv4(), + connection_token: connection_token, provider_slug: 'zendesk', token_type: 'oauth', access_token: this.cryptoService.encrypt(data.access_token), diff --git a/packages/api/src/@core/connections/crm/services/zoho/zoho.service.ts b/packages/api/src/@core/connections/crm/services/zoho/zoho.service.ts index 045e1b1b5..1ad87853c 100644 --- a/packages/api/src/@core/connections/crm/services/zoho/zoho.service.ts +++ b/packages/api/src/@core/connections/crm/services/zoho/zoho.service.ts @@ -67,6 +67,7 @@ export class ZohoConnectionService implements ICrmConnectionService { const data: ZohoOAuthResponse = res.data; this.logger.log('OAuth credentials : zoho ' + JSON.stringify(data)); let db_res; + const connection_token = uuidv4(); if (isNotUnique) { db_res = await this.prisma.connections.update({ @@ -90,6 +91,7 @@ export class ZohoConnectionService implements ICrmConnectionService { db_res = await this.prisma.connections.create({ data: { id_connection: uuidv4(), + connection_token: connection_token, provider_slug: 'zoho', token_type: 'oauth', access_token: this.cryptoService.encrypt(data.access_token), diff --git a/packages/api/src/@core/connections/ticketing/services/front/front.service.ts b/packages/api/src/@core/connections/ticketing/services/front/front.service.ts index 5a984357e..8a7c793c8 100644 --- a/packages/api/src/@core/connections/ticketing/services/front/front.service.ts +++ b/packages/api/src/@core/connections/ticketing/services/front/front.service.ts @@ -65,6 +65,7 @@ export class FrontConnectionService implements ITicketingConnectionService { ); let db_res; + const connection_token = uuidv4(); if (isNotUnique) { db_res = await this.prisma.connections.update({ @@ -85,6 +86,7 @@ export class FrontConnectionService implements ITicketingConnectionService { db_res = await this.prisma.connections.create({ data: { id_connection: uuidv4(), + connection_token: connection_token, provider_slug: 'front', token_type: 'oauth', access_token: this.cryptoService.encrypt(data.access_token), diff --git a/packages/api/src/@core/connections/ticketing/services/github/github.service.ts b/packages/api/src/@core/connections/ticketing/services/github/github.service.ts index bef9c245a..0fe22caf0 100644 --- a/packages/api/src/@core/connections/ticketing/services/github/github.service.ts +++ b/packages/api/src/@core/connections/ticketing/services/github/github.service.ts @@ -62,6 +62,7 @@ export class GithubConnectionService implements ITicketingConnectionService { ); let db_res; + const connection_token = uuidv4(); if (isNotUnique) { db_res = await this.prisma.connections.update({ @@ -82,6 +83,7 @@ export class GithubConnectionService implements ITicketingConnectionService { db_res = await this.prisma.connections.create({ data: { id_connection: uuidv4(), + connection_token: connection_token, provider_slug: 'github', token_type: 'oauth', access_token: this.cryptoService.encrypt(data.access_token), diff --git a/packages/api/src/@core/connections/ticketing/services/ticketing.connection.service.ts b/packages/api/src/@core/connections/ticketing/services/ticketing.connection.service.ts index 572496db2..1c2deb957 100644 --- a/packages/api/src/@core/connections/ticketing/services/ticketing.connection.service.ts +++ b/packages/api/src/@core/connections/ticketing/services/ticketing.connection.service.ts @@ -40,19 +40,6 @@ export class TicketingConnectionsService { zohoLocation?: string, ) { try { - const job_resp_create = await this.prisma.events.create({ - data: { - id_event: uuidv4(), - status: 'initialized', - type: 'connection.created', - method: 'GET', - url: '/oauth/callback', - provider: providerName.toLowerCase(), - direction: '0', - timestamp: new Date(), - id_linked_user: linkedUserId, - }, - }); const serviceName = providerName.toLowerCase(); const service = this.serviceRegistry.getService(serviceName); @@ -66,19 +53,25 @@ export class TicketingConnectionsService { location: zohoLocation || null, }; const data: Connection = await service.handleCallback(callbackOpts); - await this.prisma.events.update({ - where: { - id_event: job_resp_create.id_event, - }, + + const event = await this.prisma.events.create({ data: { + id_event: uuidv4(), status: 'success', + type: 'connection.created', + method: 'GET', + url: '/oauth/callback', + provider: providerName.toLowerCase(), + direction: '0', + timestamp: new Date(), + id_linked_user: linkedUserId, }, }); await this.webhook.handleWebhook( data, 'connection.created', projectId, - job_resp_create.id_event, + event.id_event, ); } catch (error) { handleServiceError(error, this.logger); diff --git a/packages/api/src/@core/connections/ticketing/services/zendesk/zendesk.service.ts b/packages/api/src/@core/connections/ticketing/services/zendesk/zendesk.service.ts index 1b67d3c94..3534d7cd2 100644 --- a/packages/api/src/@core/connections/ticketing/services/zendesk/zendesk.service.ts +++ b/packages/api/src/@core/connections/ticketing/services/zendesk/zendesk.service.ts @@ -63,6 +63,7 @@ export class ZendeskConnectionService implements ITicketingConnectionService { ); let db_res; + const connection_token = uuidv4(); if (isNotUnique) { db_res = await this.prisma.connections.update({ @@ -81,6 +82,7 @@ export class ZendeskConnectionService implements ITicketingConnectionService { db_res = await this.prisma.connections.create({ data: { id_connection: uuidv4(), + connection_token: connection_token, provider_slug: 'zendesk_tcg', token_type: 'oauth', access_token: this.cryptoService.encrypt(data.access_token), diff --git a/packages/api/src/@core/utils/errors.ts b/packages/api/src/@core/utils/errors.ts index bd7868373..22052e6c5 100644 --- a/packages/api/src/@core/utils/errors.ts +++ b/packages/api/src/@core/utils/errors.ts @@ -4,7 +4,6 @@ import axios, { AxiosError } from 'axios'; import { Prisma } from '@prisma/client'; import { TargetObject } from './types'; import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'; -import { PinoLogger } from 'nestjs-pino'; type ServiceError = AxiosError | PrismaClientKnownRequestError | Error; diff --git a/packages/api/src/crm/contact/contact.controller.ts b/packages/api/src/crm/contact/contact.controller.ts index 32bfb5082..abf2ab0a1 100644 --- a/packages/api/src/crm/contact/contact.controller.ts +++ b/packages/api/src/crm/contact/contact.controller.ts @@ -11,7 +11,10 @@ import { } from '@nestjs/common'; import { ContactService } from './services/contact.service'; import { LoggerService } from '@@core/logger/logger.service'; -import { UnifiedContactInput } from './types/model.unified'; +import { + UnifiedContactInput, + UnifiedContactOutput, +} from './types/model.unified'; import { ApiBody, ApiOperation, @@ -21,10 +24,14 @@ import { ApiHeader, } from '@nestjs/swagger'; import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { ApiCustomResponse } from '@@core/utils/types'; @ApiTags('crm/contact') @Controller('crm/contact') export class ContactController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly contactService: ContactService, private logger: LoggerService, @@ -36,27 +43,38 @@ export class ContactController { operationId: 'getContacts', summary: 'List a batch of CRM Contacts', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original CRM software.', }) - //@ApiCustomResponse(ContactResponse) + @ApiCustomResponse(UnifiedContactOutput) @UseGuards(ApiKeyAuthGuard) @Get() - getContacts( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getContacts( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.contactService.getContacts( - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.contactService.getContacts( + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) { + throw new Error(error); + } } @ApiOperation({ @@ -71,17 +89,17 @@ export class ContactController { description: 'id of the `contact` you want to retrive.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original CRM software.', }) - //@ApiCustomResponse(ContactResponse) + @ApiCustomResponse(UnifiedContactOutput) @UseGuards(ApiKeyAuthGuard) @Get(':id') getContact( @Param('id') id: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.contactService.getContact(id, remote_data); } @@ -92,69 +110,81 @@ export class ContactController { description: 'Create a contact in any supported CRM', }) @ApiHeader({ - name: 'integrationId', + name: 'connection_token', required: true, - description: 'The integration ID', - example: '6aa2acf3-c244-4f85-848b-13a57e7abf55', - }) - @ApiHeader({ - name: 'linkedUserId', - required: true, - description: 'The linked user ID', + description: 'The connection token', example: 'b008e199-eda9-4629-bd41-a01b6195864a', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original CRM software.', }) @ApiBody({ type: UnifiedContactInput }) - //@ApiCustomResponse(ContactResponse) + @ApiCustomResponse(UnifiedContactOutput) @UseGuards(ApiKeyAuthGuard) @Post() - addContact( + async addContact( @Body() unfiedContactData: UnifiedContactInput, - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.contactService.addContact( - unfiedContactData, - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.contactService.addContact( + unfiedContactData, + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) { + throw new Error(error); + } } @ApiOperation({ operationId: 'addContacts', summary: 'Add a batch of CRM Contacts', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original CRM software.', }) @ApiBody({ type: UnifiedContactInput, isArray: true }) - //@ApiCustomResponse(ContactResponse) + @ApiCustomResponse(UnifiedContactOutput) @UseGuards(ApiKeyAuthGuard) @Post('batch') - addContacts( + async addContacts( @Body() unfiedContactData: UnifiedContactInput[], - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.contactService.batchAddContacts( - unfiedContactData, - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.contactService.batchAddContacts( + unfiedContactData, + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) { + throw new Error(error); + } } @ApiOperation({ diff --git a/packages/api/src/crm/deal/deal.controller.ts b/packages/api/src/crm/deal/deal.controller.ts index 5cf2ff386..3fd5e7b59 100644 --- a/packages/api/src/crm/deal/deal.controller.ts +++ b/packages/api/src/crm/deal/deal.controller.ts @@ -39,7 +39,7 @@ export class DealController { @ApiHeader({ name: 'integrationId', required: true }) @ApiHeader({ name: 'linkedUserId', required: true }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Crm software.', @@ -49,7 +49,7 @@ export class DealController { getDeals( @Headers('integrationId') integrationId: string, @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.dealService.getDeals(integrationId, linkedUserId, remote_data); } @@ -66,14 +66,14 @@ export class DealController { description: 'id of the you want to retrive.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Crm software.', }) //@ApiCustomResponse(DealResponse) @Get(':id') - getDeal(@Param('id') id: string, @Query('remoteData') remote_data?: boolean) { + getDeal(@Param('id') id: string, @Query('remote_data') remote_data?: boolean) { return this.dealService.getDeal(id, remote_data); } @@ -95,7 +95,7 @@ export class DealController { example: 'b008e199-eda9-4629-bd41-a01b6195864a', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Crm software.', @@ -107,7 +107,7 @@ export class DealController { @Body() unfiedDealData: UnifiedDealInput, @Headers('integrationId') integrationId: string, @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.dealService.addDeal( unfiedDealData, @@ -124,7 +124,7 @@ export class DealController { @ApiHeader({ name: 'integrationId', required: true }) @ApiHeader({ name: 'linkedUserId', required: true }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Crm software.', @@ -136,7 +136,7 @@ export class DealController { @Body() unfiedDealData: UnifiedDealInput[], @Headers('integrationId') integrationId: string, @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.dealService.batchAddDeals( unfiedDealData, diff --git a/packages/api/src/ticketing/account/account.controller.ts b/packages/api/src/ticketing/account/account.controller.ts index ec414eac3..7602edefa 100644 --- a/packages/api/src/ticketing/account/account.controller.ts +++ b/packages/api/src/ticketing/account/account.controller.ts @@ -1,4 +1,11 @@ -import { Controller, Query, Get, Param, Headers } from '@nestjs/common'; +import { + Controller, + Query, + Get, + Param, + Headers, + UseGuards, +} from '@nestjs/common'; import { LoggerService } from '@@core/logger/logger.service'; import { ApiOperation, @@ -9,10 +16,15 @@ import { } from '@nestjs/swagger'; import { ApiCustomResponse } from '@@core/utils/types'; import { AccountService } from './services/account.service'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { UnifiedAccountOutput } from './types/model.unified'; +import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; @ApiTags('ticketing/account') @Controller('ticketing/account') export class AccountController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly accountService: AccountService, private logger: LoggerService, @@ -24,27 +36,37 @@ export class AccountController { operationId: 'getAccounts', summary: 'List a batch of Accounts', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(AccountResponse) + @ApiCustomResponse(UnifiedAccountOutput) + @UseGuards(ApiKeyAuthGuard) @Get() - getAccounts( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getAccounts( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.accountService.getAccounts( - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.accountService.getAccounts( + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ @@ -59,17 +81,18 @@ export class AccountController { description: 'id of the account you want to retrieve.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(AccountResponse) + @ApiCustomResponse(UnifiedAccountOutput) + @UseGuards(ApiKeyAuthGuard) @Get(':id') getAccount( @Param('id') id: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.accountService.getAccount(id, remote_data); } diff --git a/packages/api/src/ticketing/attachment/attachment.controller.ts b/packages/api/src/ticketing/attachment/attachment.controller.ts index 2b19ef2ab..f84af6bdd 100644 --- a/packages/api/src/ticketing/attachment/attachment.controller.ts +++ b/packages/api/src/ticketing/attachment/attachment.controller.ts @@ -6,6 +6,7 @@ import { Get, Param, Headers, + UseGuards, } from '@nestjs/common'; import { LoggerService } from '@@core/logger/logger.service'; import { @@ -18,11 +19,18 @@ import { } from '@nestjs/swagger'; import { ApiCustomResponse } from '@@core/utils/types'; import { AttachmentService } from './services/attachment.service'; -import { UnifiedAttachmentInput } from './types/model.unified'; +import { + UnifiedAttachmentInput, + UnifiedAttachmentOutput, +} from './types/model.unified'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; @ApiTags('ticketing/attachment') @Controller('ticketing/attachment') export class AttachmentController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly attachmentService: AttachmentService, private logger: LoggerService, @@ -34,27 +42,37 @@ export class AttachmentController { operationId: 'getAttachments', summary: 'List a batch of Attachments', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(AttachmentResponse) + @ApiCustomResponse(UnifiedAttachmentOutput) + @UseGuards(ApiKeyAuthGuard) @Get() - getAttachments( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getAttachments( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.attachmentService.getAttachments( - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.attachmentService.getAttachments( + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ @@ -69,17 +87,18 @@ export class AttachmentController { description: 'id of the attachment you want to retrive.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(AttachmentResponse) + @ApiCustomResponse(UnifiedAttachmentOutput) + @UseGuards(ApiKeyAuthGuard) @Get(':id') getAttachment( @Param('id') id: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.attachmentService.getAttachment(id, remote_data); } @@ -96,17 +115,18 @@ export class AttachmentController { description: 'id of the attachment you want to retrive.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(AttachmentResponse) + @ApiCustomResponse(UnifiedAttachmentOutput) + @UseGuards(ApiKeyAuthGuard) @Get(':id/download') downloadAttachment( @Param('id') id: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.attachmentService.downloadAttachment(id, remote_data); } @@ -117,68 +137,78 @@ export class AttachmentController { description: 'Create a attachment in any supported Ticketing software', }) @ApiHeader({ - name: 'integrationId', + name: 'connection_token', required: true, - description: 'The integration ID', - example: '6aa2acf3-c244-4f85-848b-13a57e7abf55', - }) - @ApiHeader({ - name: 'linkedUserId', - required: true, - description: 'The linked user ID', + description: 'The connection token', example: 'b008e199-eda9-4629-bd41-a01b6195864a', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) @ApiBody({ type: UnifiedAttachmentInput }) - //@ApiCustomResponse(AttachmentResponse) + @ApiCustomResponse(UnifiedAttachmentOutput) + @UseGuards(ApiKeyAuthGuard) @Post() - addAttachment( + async addAttachment( @Body() unfiedAttachmentData: UnifiedAttachmentInput, - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.attachmentService.addAttachment( - unfiedAttachmentData, - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.attachmentService.addAttachment( + unfiedAttachmentData, + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ operationId: 'addAttachments', summary: 'Add a batch of Attachments', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) @ApiBody({ type: UnifiedAttachmentInput, isArray: true }) - //@ApiCustomResponse(AttachmentResponse) + @ApiCustomResponse(UnifiedAttachmentOutput) + @UseGuards(ApiKeyAuthGuard) @Post('batch') - addAttachments( + async addAttachments( @Body() unfiedAttachmentData: UnifiedAttachmentInput[], - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.attachmentService.batchAddAttachments( - unfiedAttachmentData, - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.attachmentService.batchAddAttachments( + unfiedAttachmentData, + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } } diff --git a/packages/api/src/ticketing/comment/comment.controller.ts b/packages/api/src/ticketing/comment/comment.controller.ts index cfd466a94..97df2c1d4 100644 --- a/packages/api/src/ticketing/comment/comment.controller.ts +++ b/packages/api/src/ticketing/comment/comment.controller.ts @@ -6,6 +6,7 @@ import { Get, Param, Headers, + UseGuards, } from '@nestjs/common'; import { LoggerService } from '@@core/logger/logger.service'; import { @@ -17,11 +18,19 @@ import { ApiHeader, } from '@nestjs/swagger'; import { CommentService } from './services/comment.service'; -import { UnifiedCommentInput } from './types/model.unified'; +import { + UnifiedCommentInput, + UnifiedCommentOutput, +} from './types/model.unified'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { ApiCustomResponse } from '@@core/utils/types'; +import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; @ApiTags('ticketing/comment') @Controller('ticketing/comment') export class CommentController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly commentService: CommentService, private logger: LoggerService, @@ -33,27 +42,37 @@ export class CommentController { operationId: 'getComments', summary: 'List a batch of Comments', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(CommentResponse) + @ApiCustomResponse(UnifiedCommentOutput) + @UseGuards(ApiKeyAuthGuard) @Get() - getComments( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getComments( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.commentService.getComments( - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.commentService.getComments( + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ @@ -68,17 +87,18 @@ export class CommentController { description: 'id of the `comment` you want to retrive.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(CommentResponse) + @ApiCustomResponse(UnifiedCommentOutput) @Get(':id') + @UseGuards(ApiKeyAuthGuard) getComment( @Param('id') id: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.commentService.getComment(id, remote_data); } @@ -89,68 +109,78 @@ export class CommentController { description: 'Create a comment in any supported Ticketing software', }) @ApiHeader({ - name: 'integrationId', + name: 'connection_token', required: true, - description: 'The integration ID', - example: '6aa2acf3-c244-4f85-848b-13a57e7abf55', - }) - @ApiHeader({ - name: 'linkedUserId', - required: true, - description: 'The linked user ID', + description: 'The connection token', example: 'b008e199-eda9-4629-bd41-a01b6195864a', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) @ApiBody({ type: UnifiedCommentInput }) - //@ApiCustomResponse(CommentResponse) + @ApiCustomResponse(UnifiedCommentOutput) + @UseGuards(ApiKeyAuthGuard) @Post() - addComment( + async addComment( @Body() unfiedCommentData: UnifiedCommentInput, - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.commentService.addComment( - unfiedCommentData, - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.commentService.addComment( + unfiedCommentData, + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ operationId: 'addComments', summary: 'Add a batch of Comments', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) @ApiBody({ type: UnifiedCommentInput, isArray: true }) - //@ApiCustomResponse(CommentResponse) + @ApiCustomResponse(UnifiedCommentOutput) + @UseGuards(ApiKeyAuthGuard) @Post('batch') - addComments( + async addComments( @Body() unfiedCommentData: UnifiedCommentInput[], - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.commentService.batchAddComments( - unfiedCommentData, - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.commentService.batchAddComments( + unfiedCommentData, + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } } diff --git a/packages/api/src/ticketing/contact/contact.controller.ts b/packages/api/src/ticketing/contact/contact.controller.ts index 9db580672..1bb6863a6 100644 --- a/packages/api/src/ticketing/contact/contact.controller.ts +++ b/packages/api/src/ticketing/contact/contact.controller.ts @@ -1,4 +1,11 @@ -import { Controller, Query, Get, Param, Headers } from '@nestjs/common'; +import { + Controller, + Query, + Get, + Param, + Headers, + UseGuards, +} from '@nestjs/common'; import { LoggerService } from '@@core/logger/logger.service'; import { ApiOperation, @@ -8,10 +15,16 @@ import { ApiTags, } from '@nestjs/swagger'; import { ContactService } from './services/contact.service'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { UnifiedContactOutput } from './types/model.unified'; +import { ApiCustomResponse } from '@@core/utils/types'; +import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; @ApiTags('ticketing/contact') @Controller('ticketing/contact') export class ContactController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly contactService: ContactService, private logger: LoggerService, @@ -23,27 +36,37 @@ export class ContactController { operationId: 'getContacts', summary: 'List a batch of Contacts', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(ContactResponse) + @ApiCustomResponse(UnifiedContactOutput) + @UseGuards(ApiKeyAuthGuard) @Get() - getContacts( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getContacts( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.contactService.getContacts( - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.contactService.getContacts( + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ @@ -58,17 +81,18 @@ export class ContactController { description: 'id of the contact you want to retrieve.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(ContactResponse) + @ApiCustomResponse(UnifiedContactOutput) @Get(':id') + @UseGuards(ApiKeyAuthGuard) getContact( @Param('id') id: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.contactService.getContact(id, remote_data); } diff --git a/packages/api/src/ticketing/tag/tag.controller.ts b/packages/api/src/ticketing/tag/tag.controller.ts index 5f857e68c..60043cbfe 100644 --- a/packages/api/src/ticketing/tag/tag.controller.ts +++ b/packages/api/src/ticketing/tag/tag.controller.ts @@ -1,4 +1,11 @@ -import { Controller, Query, Get, Param, Headers } from '@nestjs/common'; +import { + Controller, + Query, + Get, + Param, + Headers, + UseGuards, +} from '@nestjs/common'; import { LoggerService } from '@@core/logger/logger.service'; import { ApiOperation, @@ -9,10 +16,15 @@ import { } from '@nestjs/swagger'; import { ApiCustomResponse } from '@@core/utils/types'; import { TagService } from './services/tag.service'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { UnifiedTagOutput } from './types/model.unified'; +import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; @ApiTags('ticketing/tag') @Controller('ticketing/tag') export class TagController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly tagService: TagService, private logger: LoggerService, @@ -24,23 +36,33 @@ export class TagController { operationId: 'getTags', summary: 'List a batch of Tags', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(TagResponse) + @ApiCustomResponse(UnifiedTagOutput) + @UseGuards(ApiKeyAuthGuard) @Get() - getTags( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getTags( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.tagService.getTags(integrationId, linkedUserId, remote_data); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.tagService.getTags(remoteSource, linkedUserId, remote_data); + } catch (error) {} } @ApiOperation({ @@ -55,15 +77,16 @@ export class TagController { description: 'id of the tag you want to retrieve.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(TagResponse) + @ApiCustomResponse(UnifiedTagOutput) + @UseGuards(ApiKeyAuthGuard) @Get(':id') - getTag(@Param('id') id: string, @Query('remoteData') remote_data?: boolean) { + getTag(@Param('id') id: string, @Query('remote_data') remote_data?: boolean) { return this.tagService.getTag(id, remote_data); } } diff --git a/packages/api/src/ticketing/team/team.controller.ts b/packages/api/src/ticketing/team/team.controller.ts index 30c75ee59..6f01f6a79 100644 --- a/packages/api/src/ticketing/team/team.controller.ts +++ b/packages/api/src/ticketing/team/team.controller.ts @@ -1,4 +1,11 @@ -import { Controller, Query, Get, Param, Headers } from '@nestjs/common'; +import { + Controller, + Query, + Get, + Param, + Headers, + UseGuards, +} from '@nestjs/common'; import { LoggerService } from '@@core/logger/logger.service'; import { ApiOperation, @@ -9,10 +16,15 @@ import { } from '@nestjs/swagger'; import { ApiCustomResponse } from '@@core/utils/types'; import { TeamService } from './services/team.service'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { UnifiedTeamOutput } from './types/model.unified'; +import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; @ApiTags('ticketing/team') @Controller('ticketing/team') export class TeamController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly teamService: TeamService, private logger: LoggerService, @@ -24,23 +36,33 @@ export class TeamController { operationId: 'getTeams', summary: 'List a batch of Teams', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(TeamResponse) + @ApiCustomResponse(UnifiedTeamOutput) + @UseGuards(ApiKeyAuthGuard) @Get() - getTeams( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getTeams( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.teamService.getTeams(integrationId, linkedUserId, remote_data); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.teamService.getTeams(remoteSource, linkedUserId, remote_data); + } catch (error) {} } @ApiOperation({ @@ -55,15 +77,19 @@ export class TeamController { description: 'id of the team you want to retrieve.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(TeamResponse) + @ApiCustomResponse(UnifiedTeamOutput) + @UseGuards(ApiKeyAuthGuard) @Get(':id') - getTeam(@Param('id') id: string, @Query('remoteData') remote_data?: boolean) { + getTeam( + @Param('id') id: string, + @Query('remote_data') remote_data?: boolean, + ) { return this.teamService.getTeam(id, remote_data); } } diff --git a/packages/api/src/ticketing/ticket/ticket.controller.ts b/packages/api/src/ticketing/ticket/ticket.controller.ts index c234523e2..3b307ef6c 100644 --- a/packages/api/src/ticketing/ticket/ticket.controller.ts +++ b/packages/api/src/ticketing/ticket/ticket.controller.ts @@ -7,6 +7,7 @@ import { Patch, Param, Headers, + UseGuards, } from '@nestjs/common'; import { LoggerService } from '@@core/logger/logger.service'; import { @@ -19,11 +20,15 @@ import { } from '@nestjs/swagger'; import { ApiCustomResponse } from '@@core/utils/types'; import { TicketService } from './services/ticket.service'; -import { UnifiedTicketInput } from './types/model.unified'; +import { UnifiedTicketInput, UnifiedTicketOutput } from './types/model.unified'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; @ApiTags('ticketing/ticket') @Controller('ticketing/ticket') export class TicketController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly ticketService: TicketService, private logger: LoggerService, @@ -35,27 +40,37 @@ export class TicketController { operationId: 'getTickets', summary: 'List a batch of Tickets', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(TicketResponse) + @ApiCustomResponse(UnifiedTicketOutput) + @UseGuards(ApiKeyAuthGuard) @Get() - getTickets( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getTickets( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.ticketService.getTickets( - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.ticketService.getTickets( + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ @@ -70,17 +85,18 @@ export class TicketController { description: 'id of the `ticket` you want to retrive.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(TicketResponse) + @ApiCustomResponse(UnifiedTicketOutput) + @UseGuards(ApiKeyAuthGuard) @Get(':id') getTicket( @Param('id') id: string, - @Query('remoteData') remote_data?: boolean, + @Query('remote_data') remote_data?: boolean, ) { return this.ticketService.getTicket(id, remote_data); } @@ -91,75 +107,86 @@ export class TicketController { description: 'Create a ticket in any supported Ticketing software', }) @ApiHeader({ - name: 'integrationId', - required: true, - description: 'The integration ID', - example: '6aa2acf3-c244-4f85-848b-13a57e7abf55', - }) - @ApiHeader({ - name: 'linkedUserId', + name: 'connection_token', required: true, - description: 'The linked user ID', + description: 'The connection token', example: 'b008e199-eda9-4629-bd41-a01b6195864a', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) @ApiBody({ type: UnifiedTicketInput }) - //@ApiCustomResponse(TicketResponse) + @ApiCustomResponse(UnifiedTicketOutput) + @UseGuards(ApiKeyAuthGuard) @Post() - addTicket( + async addTicket( @Body() unfiedTicketData: UnifiedTicketInput, - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.ticketService.addTicket( - unfiedTicketData, - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.ticketService.addTicket( + unfiedTicketData, + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ operationId: 'addTickets', summary: 'Add a batch of Tickets', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) @ApiBody({ type: UnifiedTicketInput, isArray: true }) - //@ApiCustomResponse(TicketResponse) + @ApiCustomResponse(UnifiedTicketOutput) + @UseGuards(ApiKeyAuthGuard) @Post('batch') - addTickets( + async addTickets( @Body() unfiedTicketData: UnifiedTicketInput[], - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.ticketService.batchAddTickets( - unfiedTicketData, - integrationId, - linkedUserId, - remote_data, - ); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.ticketService.batchAddTickets( + unfiedTicketData, + remoteSource, + linkedUserId, + remote_data, + ); + } catch (error) {} } @ApiOperation({ operationId: 'updateTicket', summary: 'Update a Ticket', }) + @UseGuards(ApiKeyAuthGuard) @Patch() updateTicket( @Query('id') id: string, diff --git a/packages/api/src/ticketing/user/user.controller.ts b/packages/api/src/ticketing/user/user.controller.ts index fb47cd2ca..b1eee1fc0 100644 --- a/packages/api/src/ticketing/user/user.controller.ts +++ b/packages/api/src/ticketing/user/user.controller.ts @@ -1,4 +1,11 @@ -import { Controller, Query, Get, Param, Headers } from '@nestjs/common'; +import { + Controller, + Query, + Get, + Param, + Headers, + UseGuards, +} from '@nestjs/common'; import { LoggerService } from '@@core/logger/logger.service'; import { ApiOperation, @@ -9,10 +16,15 @@ import { } from '@nestjs/swagger'; import { ApiCustomResponse } from '@@core/utils/types'; import { UserService } from './services/user.service'; +import { ConnectionUtils } from '@@core/connections/@utils'; +import { UnifiedUserOutput } from './types/model.unified'; +import { ApiKeyAuthGuard } from '@@core/auth/guards/api-key.guard'; @ApiTags('ticketing/user') @Controller('ticketing/user') export class UserController { + private readonly connectionUtils = new ConnectionUtils(); + constructor( private readonly userService: UserService, private logger: LoggerService, @@ -24,23 +36,33 @@ export class UserController { operationId: 'getUsers', summary: 'List a batch of Users', }) - @ApiHeader({ name: 'integrationId', required: true }) - @ApiHeader({ name: 'linkedUserId', required: true }) + @ApiHeader({ + name: 'connection_token', + required: true, + description: 'The connection token', + example: 'b008e199-eda9-4629-bd41-a01b6195864a', + }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(UserResponse) + @ApiCustomResponse(UnifiedUserOutput) + @UseGuards(ApiKeyAuthGuard) @Get() - getUsers( - @Headers('integrationId') integrationId: string, - @Headers('linkedUserId') linkedUserId: string, - @Query('remoteData') remote_data?: boolean, + async getUsers( + @Headers('connection_token') connection_token: string, + @Query('remote_data') remote_data?: boolean, ) { - return this.userService.getUsers(integrationId, linkedUserId, remote_data); + try { + const { linkedUserId, remoteSource } = + await this.connectionUtils.getConnectionMetadataFromConnectionToken( + connection_token, + ); + return this.userService.getUsers(remoteSource, linkedUserId, remote_data); + } catch (error) {} } @ApiOperation({ @@ -55,15 +77,19 @@ export class UserController { description: 'id of the user you want to retrieve.', }) @ApiQuery({ - name: 'remoteData', + name: 'remote_data', required: false, type: Boolean, description: 'Set to true to include data from the original Ticketing software.', }) - //@ApiCustomResponse(UserResponse) + @ApiCustomResponse(UnifiedUserOutput) + @UseGuards(ApiKeyAuthGuard) @Get(':id') - getUser(@Param('id') id: string, @Query('remoteData') remote_data?: boolean) { + getUser( + @Param('id') id: string, + @Query('remote_data') remote_data?: boolean, + ) { return this.userService.getUser(id, remote_data); } } diff --git a/packages/api/swagger/swagger-spec.json b/packages/api/swagger/swagger-spec.json index aa4896817..c6e62ec8d 100644 --- a/packages/api/swagger/swagger-spec.json +++ b/packages/api/swagger/swagger-spec.json @@ -666,7 +666,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original CRM software.", @@ -708,7 +708,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original CRM software.", @@ -775,7 +775,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original CRM software.", @@ -816,7 +816,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original CRM software.", @@ -870,7 +870,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Crm software.", @@ -912,7 +912,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Crm software.", @@ -979,7 +979,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Crm software.", @@ -1020,7 +1020,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Crm software.", @@ -1074,7 +1074,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1116,7 +1116,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1183,7 +1183,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1224,7 +1224,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1278,7 +1278,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1320,7 +1320,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1365,7 +1365,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1406,7 +1406,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1460,7 +1460,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1495,7 +1495,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1536,7 +1536,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1578,7 +1578,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1623,7 +1623,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1658,7 +1658,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1699,7 +1699,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1753,7 +1753,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1788,7 +1788,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1829,7 +1829,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1864,7 +1864,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1905,7 +1905,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1940,7 +1940,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -1981,7 +1981,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.", @@ -2016,7 +2016,7 @@ } }, { - "name": "remoteData", + "name": "remote_data", "required": false, "in": "query", "description": "Set to true to include data from the original Ticketing software.",