From c23a457ec4ed421a9a34bc80d904e49bba3dda66 Mon Sep 17 00:00:00 2001 From: nael Date: Fri, 5 Jan 2024 19:39:10 +0100 Subject: [PATCH] :construction: Upadted attachment, comment and ticket relationship --- .../attachment/services/attachment.service.ts | 123 +------- .../attachment/services/front/index.ts | 70 ----- .../attachment/services/front/mappers.ts | 43 --- .../attachment/services/front/types.ts | 5 - .../attachment/services/github/index.ts | 69 ----- .../attachment/services/github/mappers.ts | 28 -- .../attachment/services/github/types.ts | 6 - .../attachment/services/zendesk/index.ts | 80 ------ .../attachment/services/zendesk/mappers.ts | 43 --- .../attachment/services/zendesk/types.ts | 7 - .../ticketing/attachment/sync/sync.service.ts | 267 ------------------ .../attachment/types/model.unified.ts | 1 - .../ticketing/comment/services/front/index.ts | 24 +- .../comment/services/front/mappers.ts | 4 +- .../comment/services/github/index.ts | 4 +- .../comment/services/hubspot/index.ts | 4 +- .../comment/services/zendesk/index.ts | 39 ++- .../comment/services/zendesk/mappers.ts | 6 +- .../ticketing/ticket/services/front/index.ts | 20 +- .../ticket/services/front/mappers.ts | 6 +- .../ticket/services/zendesk/index.ts | 37 ++- .../ticket/services/zendesk/mappers.ts | 6 +- .../api/src/ticketing/ticket/utils/index.ts | 36 --- .../api/src/ticketing/ticketing.module.ts | 5 +- 24 files changed, 129 insertions(+), 804 deletions(-) delete mode 100644 packages/api/src/ticketing/attachment/services/front/index.ts delete mode 100644 packages/api/src/ticketing/attachment/services/front/mappers.ts delete mode 100644 packages/api/src/ticketing/attachment/services/front/types.ts delete mode 100644 packages/api/src/ticketing/attachment/services/github/index.ts delete mode 100644 packages/api/src/ticketing/attachment/services/github/mappers.ts delete mode 100644 packages/api/src/ticketing/attachment/services/github/types.ts delete mode 100644 packages/api/src/ticketing/attachment/services/zendesk/index.ts delete mode 100644 packages/api/src/ticketing/attachment/services/zendesk/mappers.ts delete mode 100644 packages/api/src/ticketing/attachment/services/zendesk/types.ts delete mode 100644 packages/api/src/ticketing/attachment/sync/sync.service.ts diff --git a/packages/api/src/ticketing/attachment/services/attachment.service.ts b/packages/api/src/ticketing/attachment/services/attachment.service.ts index 9875ff5e0..f5c729ea1 100644 --- a/packages/api/src/ticketing/attachment/services/attachment.service.ts +++ b/packages/api/src/ticketing/attachment/services/attachment.service.ts @@ -9,13 +9,7 @@ import { UnifiedAttachmentInput, UnifiedAttachmentOutput, } from '../types/model.unified'; -import { AttachmentResponse, IAttachmentService } from '../types'; -import { desunify } from '@@core/utils/unification/desunify'; -import { TicketingObject } from '@ticketing/@utils/@types'; -import { FieldMappingService } from '@@core/field-mapping/field-mapping.service'; -import { unify } from '@@core/utils/unification/unify'; -import { ServiceRegistry } from './registry.service'; -import { OriginalAttachmentOutput } from '@@core/utils/types/original/original.ticketing'; +import { AttachmentResponse } from '../types'; @Injectable() export class AttachmentService { @@ -23,8 +17,6 @@ export class AttachmentService { private prisma: PrismaService, private logger: LoggerService, private webhook: WebhookService, - private fieldMappingService: FieldMappingService, - private serviceRegistry: ServiceRegistry, ) { this.logger.setContext(AttachmentService.name); } @@ -81,47 +73,14 @@ export class AttachmentService { }); if (!linkedUser) throw new Error('Linked User Not Found'); - //TODO - // Retrieve custom field mappings - // get potential fieldMappings and extract the original properties name - const customFieldMappings = - await this.fieldMappingService.getCustomFieldMappings( - integrationId, - linkedUserId, - 'attachment', - ); - //desunify the data according to the target obj wanted - const desunifiedObject = await desunify({ - sourceObject: unifiedAttachmentData, - targetType: TicketingObject.attachment, - providerName: integrationId, - customFieldMappings: unifiedAttachmentData.field_mappings - ? customFieldMappings - : [], - }); - - const service: IAttachmentService = - this.serviceRegistry.getService(integrationId); - const resp: ApiResponse = - await service.addAttachment(desunifiedObject, linkedUserId); - - //unify the data according to the target obj wanted - const unifiedObject = (await unify({ - sourceObject: [resp.data], - targetType: TicketingObject.attachment, - providerName: integrationId, - customFieldMappings: customFieldMappings, - })) as UnifiedAttachmentOutput[]; + //EXCEPTION: for Attachments we directly store them inside our db (no raw call to the provider) + //the actual job to retrieve the attachment info would be done inside /comments // add the attachment inside our db - const source_attachment = resp.data; - const target_attachment = unifiedObject[0]; - const originId = - 'id' in source_attachment ? String(source_attachment.id) : undefined; //TODO const existingAttachment = await this.prisma.tcg_attachments.findFirst({ where: { - remote_id: originId, + file_name: unifiedAttachmentData.file_name, remote_platform: integrationId, id_linked_user: linkedUserId, }, @@ -136,22 +95,20 @@ export class AttachmentService { id_tcg_attachment: existingAttachment.id_tcg_attachment, }, data: { - //TODO + file_name: unifiedAttachmentData.file_name, modified_at: new Date(), }, }); unique_ticketing_attachment_id = res.id_tcg_attachment; } else { // Create a new attachment - this.logger.log('not existing attachment ' + target_attachment); + this.logger.log('not existing attachment '); const data = { id_tcg_attachment: uuidv4(), - //TODO - + file_name: unifiedAttachmentData.file_name, created_at: new Date(), modified_at: new Date(), id_linked_user: linkedUserId, - remote_id: originId, remote_platform: integrationId, }; @@ -161,77 +118,15 @@ export class AttachmentService { unique_ticketing_attachment_id = res.id_tcg_attachment; } - // check duplicate or existing values - if ( - target_attachment.field_mappings && - target_attachment.field_mappings.length > 0 - ) { - const entity = await this.prisma.entity.create({ - data: { - id_entity: uuidv4(), - ressource_owner_id: unique_ticketing_attachment_id, - }, - }); - - for (const mapping of target_attachment.field_mappings) { - const attribute = await this.prisma.attribute.findFirst({ - where: { - slug: Object.keys(mapping)[0], - source: integrationId, - id_consumer: linkedUserId, - }, - }); - - if (attribute) { - await this.prisma.value.create({ - data: { - id_value: uuidv4(), - data: Object.values(mapping)[0] || 'null', - attribute: { - connect: { - id_attribute: attribute.id_attribute, - }, - }, - entity: { - connect: { - id_entity: entity.id_entity, - }, - }, - }, - }); - } - } - } - if (remote_data) { - //insert remote_data in db - await this.prisma.remote_data.upsert({ - where: { - ressource_owner_id: unique_ticketing_attachment_id, - }, - create: { - id_remote_data: uuidv4(), - ressource_owner_id: unique_ticketing_attachment_id, - format: 'json', - data: JSON.stringify(source_attachment), - created_at: new Date(), - }, - update: { - data: JSON.stringify(source_attachment), - created_at: new Date(), - }, - }); - } - const result_attachment = await this.getAttachment( unique_ticketing_attachment_id, remote_data, ); - const status_resp = resp.statusCode === 201 ? 'success' : 'fail'; const event = await this.prisma.events.create({ data: { id_event: uuidv4(), - status: status_resp, + status: 'success', type: 'ticketing.attachment.push', //sync, push or pull method: 'POST', url: '/ticketing/attachment', @@ -248,7 +143,7 @@ export class AttachmentService { linkedUser.id_project, event.id_event, ); - return { ...resp, data: result_attachment.data }; + return { statusCode: 201, data: result_attachment.data }; } catch (error) { handleServiceError(error, this.logger); } diff --git a/packages/api/src/ticketing/attachment/services/front/index.ts b/packages/api/src/ticketing/attachment/services/front/index.ts deleted file mode 100644 index 0714ce137..000000000 --- a/packages/api/src/ticketing/attachment/services/front/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { LoggerService } from '@@core/logger/logger.service'; -import { PrismaService } from '@@core/prisma/prisma.service'; -import { EncryptionService } from '@@core/encryption/encryption.service'; -import { TicketingObject } from '@ticketing/@utils/@types'; -import { ApiResponse } from '@@core/utils/types'; -import axios from 'axios'; -import { ActionType, handleServiceError } from '@@core/utils/errors'; -import { ServiceRegistry } from '../registry.service'; -import { IAttachmentService } from '@ticketing/attachment/types'; -import { FrontAttachmentInput, FrontAttachmentOutput } from './types'; - -@Injectable() -export class FrontService implements IAttachmentService { - constructor( - private prisma: PrismaService, - private logger: LoggerService, - private cryptoService: EncryptionService, - private registry: ServiceRegistry, - ) { - this.logger.setContext( - TicketingObject.attachment.toUpperCase() + ':' + FrontService.name, - ); - this.registry.registerService('front', this); - } - - async addAttachment( - attachmentData: FrontAttachmentInput, - linkedUserId: string, - ): Promise> { - return; - } - - async syncAttachments( - linkedUserId: string, - ): Promise> { - try { - const connection = await this.prisma.connections.findFirst({ - where: { - id_linked_user: linkedUserId, - provider_slug: 'front', - }, - }); - - const resp = await axios.get('https://api2.frontapp.com/teammates', { - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${this.cryptoService.decrypt( - connection.access_token, - )}`, - }, - }); - this.logger.log(`Synced front attachments !`); - - return { - data: resp.data._results, - message: 'Front attachments retrieved', - statusCode: 200, - }; - } catch (error) { - handleServiceError( - error, - this.logger, - 'Front', - TicketingObject.attachment, - ActionType.GET, - ); - } - } -} diff --git a/packages/api/src/ticketing/attachment/services/front/mappers.ts b/packages/api/src/ticketing/attachment/services/front/mappers.ts deleted file mode 100644 index 164cd3ef4..000000000 --- a/packages/api/src/ticketing/attachment/services/front/mappers.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { IAttachmentMapper } from '@ticketing/attachment/types'; -import { FrontAttachmentInput, FrontAttachmentOutput } from './types'; -import { - UnifiedAttachmentInput, - UnifiedAttachmentOutput, -} from '@ticketing/attachment/types/model.unified'; - -export class FrontAttachmentMapper implements IAttachmentMapper { - desunify( - source: UnifiedAttachmentInput, - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): FrontAttachmentInput { - return; - } - - unify( - source: FrontAttachmentOutput | FrontAttachmentOutput[], - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): UnifiedAttachmentOutput | UnifiedAttachmentOutput[] { - // If the source is not an array, convert it to an array for mapping - const sourcesArray = Array.isArray(source) ? source : [source]; - - return sourcesArray.map((ticket) => - this.mapSingleTicketToUnified(ticket, customFieldMappings), - ); - } - - private mapSingleTicketToUnified( - ticket: FrontAttachmentOutput, - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): UnifiedAttachmentOutput { - return; - } -} diff --git a/packages/api/src/ticketing/attachment/services/front/types.ts b/packages/api/src/ticketing/attachment/services/front/types.ts deleted file mode 100644 index 6bdd606aa..000000000 --- a/packages/api/src/ticketing/attachment/services/front/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type FrontAttachmentInput = { - id: string; -}; - -export type FrontAttachmentOutput = FrontAttachmentInput; diff --git a/packages/api/src/ticketing/attachment/services/github/index.ts b/packages/api/src/ticketing/attachment/services/github/index.ts deleted file mode 100644 index 63e842989..000000000 --- a/packages/api/src/ticketing/attachment/services/github/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { LoggerService } from '@@core/logger/logger.service'; -import { PrismaService } from '@@core/prisma/prisma.service'; -import { EncryptionService } from '@@core/encryption/encryption.service'; -import { TicketingObject } from '@ticketing/@utils/@types'; -import { ApiResponse } from '@@core/utils/types'; -import axios from 'axios'; -import { ActionType, handleServiceError } from '@@core/utils/errors'; -import { ServiceRegistry } from '../registry.service'; -import { IAttachmentService } from '@ticketing/attachment/types'; -import { GithubAttachmentInput, GithubAttachmentOutput } from './types'; - -//TODO -@Injectable() -export class GithubService implements IAttachmentService { - constructor( - private prisma: PrismaService, - private logger: LoggerService, - private cryptoService: EncryptionService, - private registry: ServiceRegistry, - ) { - this.logger.setContext( - TicketingObject.attachment.toUpperCase() + ':' + GithubService.name, - ); - this.registry.registerService('github', this); - } - async addAttachment( - attachmentData: GithubAttachmentInput, - linkedUserId: string, - ): Promise> { - return; - } - async syncAttachments( - linkedUserId: string, - custom_properties?: string[], - ): Promise> { - try { - const connection = await this.prisma.connections.findFirst({ - where: { - id_linked_user: linkedUserId, - provider_slug: 'github', - }, - }); - const resp = await axios.get(`https://api.github.com/attachments`, { - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${this.cryptoService.decrypt( - connection.access_token, - )}`, - }, - }); - this.logger.log(`Synced github attachments !`); - - return { - data: resp.data, - message: 'Github attachments retrieved', - statusCode: 200, - }; - } catch (error) { - handleServiceError( - error, - this.logger, - 'Github', - TicketingObject.attachment, - ActionType.GET, - ); - } - } -} diff --git a/packages/api/src/ticketing/attachment/services/github/mappers.ts b/packages/api/src/ticketing/attachment/services/github/mappers.ts deleted file mode 100644 index e90772e67..000000000 --- a/packages/api/src/ticketing/attachment/services/github/mappers.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { IAttachmentMapper } from '@ticketing/attachment/types'; -import { GithubAttachmentInput, GithubAttachmentOutput } from './types'; -import { - UnifiedAttachmentInput, - UnifiedAttachmentOutput, -} from '@ticketing/attachment/types/model.unified'; - -export class GithubAttachmentMapper implements IAttachmentMapper { - desunify( - source: UnifiedAttachmentInput, - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): GithubAttachmentInput { - return; - } - - unify( - source: GithubAttachmentOutput | GithubAttachmentOutput[], - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): UnifiedAttachmentOutput | UnifiedAttachmentOutput[] { - return; - } -} diff --git a/packages/api/src/ticketing/attachment/services/github/types.ts b/packages/api/src/ticketing/attachment/services/github/types.ts deleted file mode 100644 index 690d2fb75..000000000 --- a/packages/api/src/ticketing/attachment/services/github/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type GithubAttachmentInput = { - name: string; -}; - -//TODO -export type GithubAttachmentOutput = GithubAttachmentInput; diff --git a/packages/api/src/ticketing/attachment/services/zendesk/index.ts b/packages/api/src/ticketing/attachment/services/zendesk/index.ts deleted file mode 100644 index af9af88b4..000000000 --- a/packages/api/src/ticketing/attachment/services/zendesk/index.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { LoggerService } from '@@core/logger/logger.service'; -import { PrismaService } from '@@core/prisma/prisma.service'; -import { EncryptionService } from '@@core/encryption/encryption.service'; -import { - TicketingObject, - ZendeskAttachmentInput, - ZendeskAttachmentOutput, -} from '@ticketing/@utils/@types'; -import { ApiResponse } from '@@core/utils/types'; -import axios from 'axios'; -import { ActionType, handleServiceError } from '@@core/utils/errors'; -import { DesunifyReturnType } from '@@core/utils/types/desunify.input'; -import { EnvironmentService } from '@@core/environment/environment.service'; -import { ServiceRegistry } from '../registry.service'; -import { IAttachmentService } from '@ticketing/attachment/types'; -import { OriginalAttachmentOutput } from '@@core/utils/types/original/original.ticketing'; - -@Injectable() -export class ZendeskService implements IAttachmentService { - constructor( - private prisma: PrismaService, - private logger: LoggerService, - private cryptoService: EncryptionService, - private env: EnvironmentService, - private registry: ServiceRegistry, - ) { - this.logger.setContext( - TicketingObject.attachment.toUpperCase() + ':' + ZendeskService.name, - ); - this.registry.registerService('zendesk_t', this); - } - - addAttachment( - attachmentData: ZendeskAttachmentInput, - linkedUserId: string, - ): Promise> { - return; - } - async syncAttachments( - linkedUserId: string, - custom_properties?: string[], - ): Promise> { - try { - const connection = await this.prisma.connections.findFirst({ - where: { - id_linked_user: linkedUserId, - provider_slug: 'zendesk_t', - }, - }); - - const resp = await axios.get( - `https://${this.env.getZendeskTicketingSubdomain()}.zendesk.com/api/v2/attachments`, - { - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${this.cryptoService.decrypt( - connection.access_token, - )}`, - }, - }, - ); - this.logger.log(`Synced zendesk attachments !`); - - return { - data: resp.data.attachments, - message: 'Zendesk attachments retrieved', - statusCode: 200, - }; - } catch (error) { - handleServiceError( - error, - this.logger, - 'Zendesk', - TicketingObject.attachment, - ActionType.GET, - ); - } - } -} diff --git a/packages/api/src/ticketing/attachment/services/zendesk/mappers.ts b/packages/api/src/ticketing/attachment/services/zendesk/mappers.ts deleted file mode 100644 index 8e9e402b8..000000000 --- a/packages/api/src/ticketing/attachment/services/zendesk/mappers.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { IAttachmentMapper } from '@ticketing/attachment/types'; -import { ZendeskAttachmentInput, ZendeskAttachmentOutput } from './types'; -import { - UnifiedAttachmentInput, - UnifiedAttachmentOutput, -} from '@ticketing/attachment/types/model.unified'; - -export class ZendeskAttachmentMapper implements IAttachmentMapper { - desunify( - source: UnifiedAttachmentInput, - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): ZendeskAttachmentInput { - return; - } - - unify( - source: ZendeskAttachmentOutput | ZendeskAttachmentOutput[], - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): UnifiedAttachmentOutput | UnifiedAttachmentOutput[] { - if (!Array.isArray(source)) { - return this.mapSingleAttachmentToUnified(source, customFieldMappings); - } - return source.map((ticket) => - this.mapSingleAttachmentToUnified(ticket, customFieldMappings), - ); - } - - private mapSingleAttachmentToUnified( - ticket: ZendeskAttachmentOutput, - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): UnifiedAttachmentOutput { - return; - } -} diff --git a/packages/api/src/ticketing/attachment/services/zendesk/types.ts b/packages/api/src/ticketing/attachment/services/zendesk/types.ts deleted file mode 100644 index 97083238d..000000000 --- a/packages/api/src/ticketing/attachment/services/zendesk/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type ZendeskAttachmentInput = { - _: string; -}; - -export type ZendeskAttachmentOutput = ZendeskAttachmentInput & { - id: number; // Read-only. Automatically assigned when the ticket is created. -}; diff --git a/packages/api/src/ticketing/attachment/sync/sync.service.ts b/packages/api/src/ticketing/attachment/sync/sync.service.ts deleted file mode 100644 index e7705ec38..000000000 --- a/packages/api/src/ticketing/attachment/sync/sync.service.ts +++ /dev/null @@ -1,267 +0,0 @@ -import { Injectable, OnModuleInit } from '@nestjs/common'; -import { LoggerService } from '@@core/logger/logger.service'; -import { PrismaService } from '@@core/prisma/prisma.service'; -import { NotFoundError, handleServiceError } from '@@core/utils/errors'; -import { Cron } from '@nestjs/schedule'; -import { ApiResponse, TICKETING_PROVIDERS } from '@@core/utils/types'; -import { v4 as uuidv4 } from 'uuid'; -import { FieldMappingService } from '@@core/field-mapping/field-mapping.service'; -import { unify } from '@@core/utils/unification/unify'; -import { TicketingObject } from '@ticketing/@utils/@types'; -import { WebhookService } from '@@core/webhook/webhook.service'; -import { UnifiedAttachmentOutput } from '../types/model.unified'; -import { IAttachmentService } from '../types'; -import { ServiceRegistry } from '../services/registry.service'; -import { OriginalAttachmentOutput } from '@@core/utils/types/original/original.ticketing'; -import { tcg_attachments as TicketingAttachment } from '@prisma/client'; - -@Injectable() -export class SyncService implements OnModuleInit { - constructor( - private prisma: PrismaService, - private logger: LoggerService, - private webhook: WebhookService, - private fieldMappingService: FieldMappingService, - private serviceRegistry: ServiceRegistry, - ) { - this.logger.setContext(SyncService.name); - } - - async onModuleInit() { - try { - await this.syncAttachments(); - } catch (error) { - handleServiceError(error, this.logger); - } - } - - @Cron('*/20 * * * *') - //function used by sync worker which populate our tcg_attachments table - //its role is to fetch all attachments from providers 3rd parties and save the info inside our db - async syncAttachments() { - try { - this.logger.log(`Syncing attachments....`); - const defaultOrg = await this.prisma.organizations.findFirst({ - where: { - name: 'Acme Inc', - }, - }); - - const defaultProject = await this.prisma.projects.findFirst({ - where: { - id_organization: defaultOrg.id_organization, - name: 'Project 1', - }, - }); - const id_project = defaultProject.id_project; - const linkedUsers = await this.prisma.linked_users.findMany({ - where: { - id_project: id_project, - }, - }); - linkedUsers.map(async (linkedUser) => { - try { - const providers = TICKETING_PROVIDERS; - for (const provider of providers) { - try { - //call the sync attachments for every ticket of the linkedUser (a attachment is tied to a ticket) - const tickets = await this.prisma.tcg_tickets.findMany({ - where: { - remote_platform: provider, - events: { - id_linked_user: linkedUser.id_linked_user, - }, - }, - }); - for (const ticket of tickets) { - await this.syncAttachmentsForLinkedUser( - provider, - linkedUser.id_linked_user, - id_project, - ticket.id_tcg_ticket, - ); - } - } catch (error) { - handleServiceError(error, this.logger); - } - } - } catch (error) { - handleServiceError(error, this.logger); - } - }); - } catch (error) { - handleServiceError(error, this.logger); - } - } - - //todo: HANDLE DATA REMOVED FROM PROVIDER - async syncAttachmentsForLinkedUser( - integrationId: string, - linkedUserId: string, - id_project: string, - id_ticket: string, - ) { - try { - this.logger.log( - `Syncing ${integrationId} attachments for linkedUser ${linkedUserId}`, - ); - // check if linkedUser has a connection if not just stop sync - const connection = await this.prisma.connections.findFirst({ - where: { - id_linked_user: linkedUserId, - provider_slug: integrationId, - }, - }); - if (!connection) throw new Error('connection not found'); - - // get potential fieldMappings and extract the original properties name - const customFieldMappings = - await this.fieldMappingService.getCustomFieldMappings( - integrationId, - linkedUserId, - 'attachment', - ); - const remoteProperties: string[] = customFieldMappings.map( - (mapping) => mapping.remote_id, - ); - - const service: IAttachmentService = - this.serviceRegistry.getService(integrationId); - const resp: ApiResponse = - await service.syncAttachments(linkedUserId, remoteProperties); - - const sourceObject: OriginalAttachmentOutput[] = resp.data; - //this.logger.log('SOURCE OBJECT DATA = ' + JSON.stringify(sourceObject)); - //unify the data according to the target obj wanted - const unifiedObject = (await unify({ - sourceObject, - targetType: TicketingObject.attachment, - providerName: integrationId, - customFieldMappings, - })) as UnifiedAttachmentOutput[]; - - //TODO - const attachmentsIds = sourceObject.map((attachment) => - 'id' in attachment ? String(attachment.id) : undefined, - ); - //insert the data in the DB with the fieldMappings (value table) - const attachments_data = await this.saveAttachmentsInDb( - linkedUserId, - unifiedObject, - attachmentsIds, - integrationId, - id_ticket, - sourceObject, - ); - const event = await this.prisma.events.create({ - data: { - id_event: uuidv4(), - status: 'success', - type: 'ticketing.attachment.pulled', - method: 'PULL', - url: '/pull', - provider: integrationId, - direction: '0', - timestamp: new Date(), - id_linked_user: linkedUserId, - }, - }); - await this.webhook.handleWebhook( - attachments_data, - 'ticketing.attachment.pulled', - id_project, - event.id_event, - ); - } catch (error) { - handleServiceError(error, this.logger); - } - } - - async saveAttachmentsInDb( - linkedUserId: string, - attachments: UnifiedAttachmentOutput[], - originIds: string[], - originSource: string, - id_ticket: string, - remote_data: Record[], - ): Promise { - try { - let attachments_results: TicketingAttachment[] = []; - for (let i = 0; i < attachments.length; i++) { - const attachment = attachments[i]; - const originId = originIds[i]; - - if (!originId || originId == '') { - throw new NotFoundError(`Origin id not there, found ${originId}`); - } - - const existingAttachment = await this.prisma.tcg_attachments.findFirst({ - where: { - remote_id: originId, - remote_platform: originSource, - id_linked_user: linkedUserId, - }, - }); - - let unique_ticketing_attachment_id: string; - - if (existingAttachment) { - // Update the existing attachment - const res = await this.prisma.tcg_attachments.update({ - where: { - id_tcg_attachment: existingAttachment.id_tcg_attachment, - }, - data: { - //TODO - id_tcg_ticket: id_ticket, - modified_at: new Date(), - }, - }); - unique_ticketing_attachment_id = res.id_tcg_attachment; - attachments_results = [...attachments_results, res]; - } else { - // Create a new attachment - this.logger.log('attachment not exists'); - const data = { - id_tcg_attachment: uuidv4(), - //TODO - created_at: new Date(), - modified_at: new Date(), - id_tcg_ticket: id_ticket, - id_linkedUser: linkedUserId, - remote_id: originId, - remote_platform: originSource, - //TODO; id_tcg_contact String? @db.Uuid - //TODO; id_tcg_user String? @db.Uuid - }; - const res = await this.prisma.tcg_attachments.create({ - data: data, - }); - attachments_results = [...attachments_results, res]; - unique_ticketing_attachment_id = res.id_tcg_attachment; - } - - //insert remote_data in db - await this.prisma.remote_data.upsert({ - where: { - ressource_owner_id: unique_ticketing_attachment_id, - }, - create: { - id_remote_data: uuidv4(), - ressource_owner_id: unique_ticketing_attachment_id, - format: 'json', - data: JSON.stringify(remote_data[i]), - created_at: new Date(), - }, - update: { - data: JSON.stringify(remote_data[i]), - created_at: new Date(), - }, - }); - } - return attachments_results; - } catch (error) { - handleServiceError(error, this.logger); - } - } -} diff --git a/packages/api/src/ticketing/attachment/types/model.unified.ts b/packages/api/src/ticketing/attachment/types/model.unified.ts index 90785cde2..a931ecf27 100644 --- a/packages/api/src/ticketing/attachment/types/model.unified.ts +++ b/packages/api/src/ticketing/attachment/types/model.unified.ts @@ -1,6 +1,5 @@ export class UnifiedAttachmentInput { file_name: string; - ticket_id?: string; file_url: string; uploader?: string; field_mappings?: Record[]; diff --git a/packages/api/src/ticketing/comment/services/front/index.ts b/packages/api/src/ticketing/comment/services/front/index.ts index a0663be98..5487b027c 100644 --- a/packages/api/src/ticketing/comment/services/front/index.ts +++ b/packages/api/src/ticketing/comment/services/front/index.ts @@ -3,12 +3,11 @@ import { LoggerService } from '@@core/logger/logger.service'; import { PrismaService } from '@@core/prisma/prisma.service'; import { EncryptionService } from '@@core/encryption/encryption.service'; import { ApiResponse } from '@@core/utils/types'; -import { DesunifyReturnType } from '@@core/utils/types/desunify.input'; import axios from 'axios'; import { ActionType, handleServiceError } from '@@core/utils/errors'; import { ICommentService } from '@ticketing/comment/types'; import { TicketingObject } from '@ticketing/@utils/@types'; -import { FrontCommentOutput } from './types'; +import { FrontCommentInput, FrontCommentOutput } from './types'; import { OriginalCommentOutput } from '@@core/utils/types/original/original.ticketing'; import { ServiceRegistry } from '../registry.service'; @@ -26,7 +25,7 @@ export class FrontService implements ICommentService { this.registry.registerService('front', this); } async addComment( - commentData: DesunifyReturnType, + commentData: FrontCommentInput, linkedUserId: string, remoteIdTicket: string, ): Promise> { @@ -38,7 +37,24 @@ export class FrontService implements ICommentService { provider_slug: 'front', }, }); - const dataBody = commentData; + const uuids = commentData.attachments; + let uploads = []; + uuids.map(async (uuid) => { + const res = await this.prisma.tcg_attachments.findUnique({ + where: { + id_tcg_attachment: uuid, + }, + }); + if (!res) throw new Error(`tcg_attachment not found for uuid ${uuid}`); + //TODO: construct the right binary attachment + //get the AWS s3 right file + const url = res.file_url; + uploads = [...uploads, url]; + }); + const dataBody = { + ...commentData, + attachments: uploads, + }; const resp = await axios.post( `https://api2.frontapp.com/conversations/${remoteIdTicket}/comments`, JSON.stringify(dataBody), diff --git a/packages/api/src/ticketing/comment/services/front/mappers.ts b/packages/api/src/ticketing/comment/services/front/mappers.ts index c9109bae0..0e0b55210 100644 --- a/packages/api/src/ticketing/comment/services/front/mappers.ts +++ b/packages/api/src/ticketing/comment/services/front/mappers.ts @@ -19,9 +19,7 @@ export class FrontCommentMapper implements ICommentMapper { const result: FrontCommentInput = { body: source.body, author_id: source.user_id || source.contact_id, //TODO: make sure either one is passed - attachments: source.attachments - ? await this.utils.get_Front_AttachmentsFromUuid(source.attachments) - : [], + attachments: source.attachments, }; return result; } diff --git a/packages/api/src/ticketing/comment/services/github/index.ts b/packages/api/src/ticketing/comment/services/github/index.ts index 0ce4de98b..8c1dae630 100644 --- a/packages/api/src/ticketing/comment/services/github/index.ts +++ b/packages/api/src/ticketing/comment/services/github/index.ts @@ -10,7 +10,7 @@ import { ICommentService } from '@ticketing/comment/types'; import { TicketingObject } from '@ticketing/@utils/@types'; import { OriginalCommentOutput } from '@@core/utils/types/original/original.ticketing'; import { ServiceRegistry } from '../registry.service'; -import { GithubCommentOutput } from './types'; +import { GithubCommentInput, GithubCommentOutput } from './types'; @Injectable() export class GithubService implements ICommentService { @@ -26,7 +26,7 @@ export class GithubService implements ICommentService { this.registry.registerService('github', this); } async addComment( - commentData: DesunifyReturnType, + commentData: GithubCommentInput, linkedUserId: string, remoteIdTicket: string, ): Promise> { diff --git a/packages/api/src/ticketing/comment/services/hubspot/index.ts b/packages/api/src/ticketing/comment/services/hubspot/index.ts index ccab00f34..d993b0e44 100644 --- a/packages/api/src/ticketing/comment/services/hubspot/index.ts +++ b/packages/api/src/ticketing/comment/services/hubspot/index.ts @@ -10,7 +10,7 @@ import { ICommentService } from '@ticketing/comment/types'; import { TicketingObject } from '@ticketing/@utils/@types'; import { OriginalCommentOutput } from '@@core/utils/types/original/original.ticketing'; import { ServiceRegistry } from '../registry.service'; -import { HubspotCommentOutput } from './types'; +import { HubspotCommentInput, HubspotCommentOutput } from './types'; @Injectable() export class HubspotService implements ICommentService { @@ -26,7 +26,7 @@ export class HubspotService implements ICommentService { this.registry.registerService('hubspot_t', this); } async addComment( - commentData: DesunifyReturnType, + commentData: HubspotCommentInput, linkedUserId: string, remoteIdTicket: string, ): Promise> { diff --git a/packages/api/src/ticketing/comment/services/zendesk/index.ts b/packages/api/src/ticketing/comment/services/zendesk/index.ts index 1a94351c2..8ce85b684 100644 --- a/packages/api/src/ticketing/comment/services/zendesk/index.ts +++ b/packages/api/src/ticketing/comment/services/zendesk/index.ts @@ -10,7 +10,7 @@ import { ICommentService } from '@ticketing/comment/types'; import { TicketingObject } from '@ticketing/@utils/@types'; import { OriginalCommentOutput } from '@@core/utils/types/original/original.ticketing'; import { ServiceRegistry } from '../registry.service'; -import { ZendeskCommentOutput } from './types'; +import { ZendeskCommentInput, ZendeskCommentOutput } from './types'; import { EnvironmentService } from '@@core/environment/environment.service'; @Injectable() export class ZendeskService implements ICommentService { @@ -26,8 +26,9 @@ export class ZendeskService implements ICommentService { ); this.registry.registerService('zendesk_t', this); } + async addComment( - commentData: DesunifyReturnType, + commentData: ZendeskCommentInput, linkedUserId: string, remoteIdTicket: string, ): Promise> { @@ -38,9 +39,41 @@ export class ZendeskService implements ICommentService { provider_slug: 'zendesk_t', }, }); + + // We must fetch tokens from zendesk with the commentData.uploads array of Attachment uuids + const uuids = commentData.uploads; + let uploads = []; + uuids.map(async (uuid) => { + const res = await this.prisma.tcg_attachments.findUnique({ + where: { + id_tcg_attachment: uuid, + }, + }); + if (!res) throw new Error(`tcg_attachment not found for uuid ${uuid}`); + + //TODO:; fetch the right file from AWS s3 + const s3File = ''; + const url = `https://${this.env.getZendeskTicketingSubdomain()}.zendesk.com/api/v2/uploads.json?filename=${ + res.file_name + }`; + + const resp = await axios.get(url, { + headers: { + 'Content-Type': 'image/png', //TODO: get the right content-type given a file name extension + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + uploads = [...uploads, resp.data.upload.token]; + }); + const finalData = { + ...commentData, + uploads: uploads, + }; const dataBody = { ticket: { - comment: commentData, + comment: finalData, }, }; //to add a comment on Zendesk you must update a ticket using the Ticket API diff --git a/packages/api/src/ticketing/comment/services/zendesk/mappers.ts b/packages/api/src/ticketing/comment/services/zendesk/mappers.ts index 87190227b..c6cabb783 100644 --- a/packages/api/src/ticketing/comment/services/zendesk/mappers.ts +++ b/packages/api/src/ticketing/comment/services/zendesk/mappers.ts @@ -26,11 +26,7 @@ export class ZendeskCommentMapper implements ICommentMapper { ? parseInt(source.contact_id) : undefined, //TODO: make sure either one is passed type: 'Comment', - uploads: source.attachments - ? await this.utils.get_Zendesk_AttachmentsTokensFromUuid( - source.attachments, - ) - : [], //fetch token attachments for this uuid + uploads: source.attachments, //we let the array of uuids on purpose (it will be modified in the given service on the fly!) }; return result; diff --git a/packages/api/src/ticketing/ticket/services/front/index.ts b/packages/api/src/ticketing/ticket/services/front/index.ts index 59311a1d3..6d18d12c6 100644 --- a/packages/api/src/ticketing/ticket/services/front/index.ts +++ b/packages/api/src/ticketing/ticket/services/front/index.ts @@ -34,7 +34,25 @@ export class FrontService implements ITicketService { provider_slug: 'front', }, }); - const dataBody = ticketData; + + const uuids = ticketData.comment.attachments; + let uploads = []; + uuids.map(async (uuid) => { + const res = await this.prisma.tcg_attachments.findUnique({ + where: { + id_tcg_attachment: uuid, + }, + }); + if (!res) throw new Error(`tcg_attachment not found for uuid ${uuid}`); + //TODO: construct the right binary attachment + //get the AWS s3 right file + const url = res.file_url; + uploads = [...uploads, url]; + }); + const dataBody = { + ...ticketData, + comment: { ...ticketData.comment, attachments: uploads }, + }; const resp = await axios.post( `https://api2.frontapp.com/conversations`, JSON.stringify(dataBody), diff --git a/packages/api/src/ticketing/ticket/services/front/mappers.ts b/packages/api/src/ticketing/ticket/services/front/mappers.ts index 8cd400dbd..c241fb025 100644 --- a/packages/api/src/ticketing/ticket/services/front/mappers.ts +++ b/packages/api/src/ticketing/ticket/services/front/mappers.ts @@ -26,11 +26,7 @@ export class FrontTicketMapper implements ITicketMapper { source.comment.creator_type === 'user' ? source.comment.user_id : source.comment.contact_id, - attachments: source.comment.attachments - ? await this.utils.get_Front_AttachmentsFromUuid( - source.comment.attachments, - ) - : [], + attachments: source.comment.attachments, }, }; diff --git a/packages/api/src/ticketing/ticket/services/zendesk/index.ts b/packages/api/src/ticketing/ticket/services/zendesk/index.ts index 947ed3bd4..bcbaaa4fb 100644 --- a/packages/api/src/ticketing/ticket/services/zendesk/index.ts +++ b/packages/api/src/ticketing/ticket/services/zendesk/index.ts @@ -39,8 +39,43 @@ export class ZendeskService implements ITicketService { provider_slug: 'zendesk_t', }, }); + + // We must fetch tokens from zendesk with the commentData.uploads array of Attachment uuids + const uuids = ticketData.comment.uploads; + let uploads = []; + uuids.map(async (uuid) => { + const res = await this.prisma.tcg_attachments.findUnique({ + where: { + id_tcg_attachment: uuid, + }, + }); + if (!res) throw new Error(`tcg_attachment not found for uuid ${uuid}`); + + //TODO:; fetch the right file from AWS s3 + const s3File = ''; + const url = `https://${this.env.getZendeskTicketingSubdomain()}.zendesk.com/api/v2/uploads.json?filename=${ + res.file_name + }`; + + const resp = await axios.get(url, { + headers: { + 'Content-Type': 'image/png', //TODO: get the right content-type given a file name extension + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + uploads = [...uploads, resp.data.upload.token]; + }); + const finalData = { + ...ticketData, + comment: { + ...ticketData.comment, + uploads: uploads, + }, + }; const dataBody = { - ticket: ticketData, + ticket: finalData, }; const resp = await axios.post( `https://${this.env.getZendeskTicketingSubdomain()}.zendesk.com/api/v2/tickets.json`, diff --git a/packages/api/src/ticketing/ticket/services/zendesk/mappers.ts b/packages/api/src/ticketing/ticket/services/zendesk/mappers.ts index f187e4ed6..082916b38 100644 --- a/packages/api/src/ticketing/ticket/services/zendesk/mappers.ts +++ b/packages/api/src/ticketing/ticket/services/zendesk/mappers.ts @@ -37,11 +37,7 @@ export class ZendeskTicketMapper implements ITicketMapper { body: source.comment.body, html_body: source.comment.html_body, public: !source.comment.is_private, - uploads: source.comment.attachments - ? await this.utils.get_Zendesk_AttachmentsTokensFromUuid( - source.comment.attachments, - ) - : [], //fetch token attachments for this uuid + uploads: source.comment.attachments, //fetch token attachments for this uuid }, }; diff --git a/packages/api/src/ticketing/ticket/utils/index.ts b/packages/api/src/ticketing/ticket/utils/index.ts index adcd25ed3..75dfcc49b 100644 --- a/packages/api/src/ticketing/ticket/utils/index.ts +++ b/packages/api/src/ticketing/ticket/utils/index.ts @@ -2,7 +2,6 @@ import { PrismaClient } from '@prisma/client'; export class Utils { private readonly prisma: PrismaClient; - constructor() { this.prisma = new PrismaClient(); } @@ -18,39 +17,4 @@ export class Utils { return res.email_address; } catch (error) {} } - - async get_Zendesk_AttachmentsTokensFromUuid(uuids: string[]) { - try { - let uploads = []; - uuids.map(async (uuid) => { - const res = await this.prisma.tcg_attachments.findUnique({ - where: { - id_tcg_attachment: uuid, - }, - select: token, - }); - if (!res) throw new Error(`tcg_attachment not found for uuid ${uuid}`); - uploads = [...uploads, res.token]; - }); - return uploads; - } catch (error) {} - } - - async get_Front_AttachmentsFromUuid(uuids: string[]) { - try { - let uploads = []; - uuids.map(async (uuid) => { - const res = await this.prisma.tcg_attachments.findUnique({ - where: { - id_tcg_attachment: uuid, - }, - }); - if (!res) throw new Error(`tcg_attachment not found for uuid ${uuid}`); - //TODO: construct the right binary attachment - const url = res.file_url; - uploads = [...uploads, url]; - }); - return uploads; - } catch (error) {} - } } diff --git a/packages/api/src/ticketing/ticketing.module.ts b/packages/api/src/ticketing/ticketing.module.ts index c293ff4aa..4e1cd7302 100644 --- a/packages/api/src/ticketing/ticketing.module.ts +++ b/packages/api/src/ticketing/ticketing.module.ts @@ -21,9 +21,6 @@ import { TeamModule } from './team/team.module'; ], providers: [], controllers: [], - exports: [ UserModule, - AttachmentModule, - ContactModule, - ], + exports: [UserModule, AttachmentModule, ContactModule], }) export class TicketingModule {}