diff --git a/CHANGELOG.md b/CHANGELOG.md index ddd50db4..065a415b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features * Webhook url by submitted template to send status updates +* Sending template approval status webhook ### Fixed diff --git a/prisma/migrations/20240725184147_create_template_table/migration.sql b/prisma/migrations/20240725184147_create_template_table/migration.sql new file mode 100644 index 00000000..0b1d6ad0 --- /dev/null +++ b/prisma/migrations/20240725184147_create_template_table/migration.sql @@ -0,0 +1,21 @@ +-- CreateTable +CREATE TABLE "Template" ( + "id" TEXT NOT NULL, + "templateId" VARCHAR(255) NOT NULL, + "name" VARCHAR(255) NOT NULL, + "template" JSONB NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Template_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Template_templateId_key" ON "Template"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Template_name_key" ON "Template"("name"); + +-- AddForeignKey +ALTER TABLE "Template" ADD CONSTRAINT "Template_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20240725202651_add_webhook_url_template_table/migration.sql b/prisma/migrations/20240725202651_add_webhook_url_template_table/migration.sql new file mode 100644 index 00000000..ecb55e49 --- /dev/null +++ b/prisma/migrations/20240725202651_add_webhook_url_template_table/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Template" ADD COLUMN "webhookUrl" VARCHAR(500); diff --git a/prisma/migrations/20240725221646_modify_token_instance_table/migration.sql b/prisma/migrations/20240725221646_modify_token_instance_table/migration.sql new file mode 100644 index 00000000..632509e0 --- /dev/null +++ b/prisma/migrations/20240725221646_modify_token_instance_table/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "Instance_token_key"; diff --git a/prisma/postgresql-schema.prisma b/prisma/postgresql-schema.prisma index 86c5cb03..48d59756 100644 --- a/prisma/postgresql-schema.prisma +++ b/prisma/postgresql-schema.prisma @@ -56,7 +56,7 @@ model Instance { integration String? @db.VarChar(100) number String? @db.VarChar(100) businessId String? @db.VarChar(100) - token String? @unique @db.VarChar(255) + token String? @db.VarChar(255) clientName String? @db.VarChar(100) createdAt DateTime? @default(now()) @db.Timestamp updatedAt DateTime? @updatedAt @db.Timestamp @@ -81,6 +81,7 @@ model Instance { OpenaiBot OpenaiBot[] OpenaiSession OpenaiSession[] OpenaiSetting OpenaiSetting? + Template Template[] } model Session { @@ -412,3 +413,15 @@ model OpenaiSetting { Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) instanceId String @unique } + +model Template { + id String @id @default(cuid()) + templateId String @unique @db.VarChar(255) + name String @unique @db.VarChar(255) + template Json @db.JsonB + webhookUrl String? @db.VarChar(500) + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String +} diff --git a/src/api/controllers/instance.controller.ts b/src/api/controllers/instance.controller.ts index abbbd34d..ecb78e40 100644 --- a/src/api/controllers/instance.controller.ts +++ b/src/api/controllers/instance.controller.ts @@ -90,7 +90,7 @@ export class InstanceController { businessId, }: InstanceDto) { try { - if (token) await this.authService.checkDuplicateToken(token); + // if (token) await this.authService.checkDuplicateToken(token); if (!token && integration === Integration.WHATSAPP_BUSINESS) { throw new BadRequestException('token is required'); @@ -623,14 +623,14 @@ export class InstanceController { // let arrayReturn = false; if (env.KEY !== key) { - const instanceByKey = await this.prismaRepository.instance.findUnique({ + const instanceByKey = await this.prismaRepository.instance.findMany({ where: { token: key, }, }); if (instanceByKey) { - name = instanceByKey.name; + name = instanceByKey[0].name; // arrayReturn = true; } else { throw new UnauthorizedException(); diff --git a/src/api/dto/template.dto.ts b/src/api/dto/template.dto.ts index 1a5f69ff..cec7d6c5 100644 --- a/src/api/dto/template.dto.ts +++ b/src/api/dto/template.dto.ts @@ -4,4 +4,5 @@ export class TemplateDto { allowCategoryChange: boolean; language: string; components: any; + webhookUrl?: string; } diff --git a/src/api/services/channels/whatsapp.business.service.ts b/src/api/services/channels/whatsapp.business.service.ts index 341ca76d..ac9de240 100644 --- a/src/api/services/channels/whatsapp.business.service.ts +++ b/src/api/services/channels/whatsapp.business.service.ts @@ -126,6 +126,7 @@ export class BusinessStartupService extends ChannelStartupService { if (!data) return; const content = data.entry[0].changes[0].value; + try { this.loadWebhook(); this.loadChatwoot(); @@ -297,6 +298,7 @@ export class BusinessStartupService extends ChannelStartupService { protected async messageHandle(received: any, database: Database, settings: any) { try { + console.log(received); let messageRaw: any; let pushName: any; diff --git a/src/api/services/template.service.ts b/src/api/services/template.service.ts index 2fd88a9e..e959be23 100644 --- a/src/api/services/template.service.ts +++ b/src/api/services/template.service.ts @@ -59,11 +59,21 @@ export class TemplateService { const response = await this.requestTemplate(postData, 'POST'); - if (!response) { - return response; + if (!response || response.error) { + throw new Error('Error to create template'); } - return response; + const template = await this.prismaRepository.template.create({ + data: { + templateId: response.id, + name: data.name, + template: response, + webhookUrl: data.webhookUrl, + instanceId: getInstance.id, + }, + }); + + return template; } catch (error) { this.logger.error(error); throw new Error('Error to create template'); diff --git a/src/api/services/webhook.service.ts b/src/api/services/webhook.service.ts index 70307e54..80df1688 100644 --- a/src/api/services/webhook.service.ts +++ b/src/api/services/webhook.service.ts @@ -1,4 +1,5 @@ import { Webhook } from '@prisma/client'; +import axios from 'axios'; import { Logger } from '../../config/logger.config'; import { InstanceDto } from '../dto/instance.dto'; @@ -33,6 +34,26 @@ export class WebhookService { public async receiveWebhook(data: any) { if (data.object === 'whatsapp_business_account') { + if (data.entry[0]?.changes[0]?.field === 'message_template_status_update') { + const template = await this.prismaRepository.template.findFirst({ + where: { templateId: `${data.entry[0].changes[0].value.message_template_id}` }, + }); + + if (!template) { + console.log('template not found'); + return; + } + + const { webhookUrl } = template; + + await axios.post(webhookUrl, data.entry[0].changes[0].value, { + headers: { + 'Content-Type': 'application/json', + }, + }); + return; + } + data.entry?.forEach(async (entry: any) => { const numberId = entry.changes[0].value.metadata.phone_number_id; diff --git a/src/validate/template.schema.ts b/src/validate/template.schema.ts index 505f076f..4adb08c0 100644 --- a/src/validate/template.schema.ts +++ b/src/validate/template.schema.ts @@ -29,6 +29,7 @@ export const templateSchema: JSONSchema7 = { allowCategoryChange: { type: 'boolean' }, language: { type: 'string' }, components: { type: 'array' }, + webhookUrl: { type: 'string' }, }, required: ['name', 'category', 'language', 'components'], ...isNotEmpty('name', 'category', 'language', 'components'),