diff --git a/Docker/.env.example b/Docker/.env.example index 18fa32bd..f3b19091 100644 --- a/Docker/.env.example +++ b/Docker/.env.example @@ -91,4 +91,7 @@ AUTHENTICATION_JWT_SECRET='L0YWtjb2w554WFqPG' AUTHENTICATION_INSTANCE_MODE=server # container or server # if you are using container mode, set the container name and the webhook url to default instance AUTHENTICATION_INSTANCE_NAME=evolution -AUTHENTICATION_INSTANCE_WEBHOOK_URL='' \ No newline at end of file +AUTHENTICATION_INSTANCE_WEBHOOK_URL='' +AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID=1 +AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN=123456 +AUTHENTICATION_INSTANCE_CHATWOOT_URL='' \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c9ef576d..726064e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -88,6 +88,9 @@ ENV AUTHENTICATION_JWT_SECRET="L=0YWt]b2w[WF>#>:&E`" ENV AUTHENTICATION_INSTANCE_NAME=$AUTHENTICATION_INSTANCE_NAME ENV AUTHENTICATION_INSTANCE_WEBHOOK_URL=$AUTHENTICATION_INSTANCE_WEBHOOK_URL +ENV AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID=$AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID +ENV AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN=$AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN +ENV AUTHENTICATION_INSTANCE_CHATWOOT_URL=$AUTHENTICATION_INSTANCE_CHATWOOT_URL ENV AUTHENTICATION_INSTANCE_MODE=$AUTHENTICATION_INSTANCE_MODE RUN npm install diff --git a/src/config/env.config.ts b/src/config/env.config.ts index 6ad188b1..d13eec07 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -98,6 +98,9 @@ export type Instance = { NAME: string; WEBHOOK_URL: string; MODE: string; + CHATWOOT_ACCOUNT_ID: string; + CHATWOOT_TOKEN: string; + CHATWOOT_URL: string; }; export type Auth = { API_KEY: ApiKey; @@ -275,6 +278,9 @@ export class ConfigService { NAME: process.env.AUTHENTICATION_INSTANCE_NAME, WEBHOOK_URL: process.env.AUTHENTICATION_INSTANCE_WEBHOOK_URL, MODE: process.env.AUTHENTICATION_INSTANCE_MODE, + CHATWOOT_ACCOUNT_ID: process.env.AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID, + CHATWOOT_TOKEN: process.env.AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN, + CHATWOOT_URL: process.env.AUTHENTICATION_INSTANCE_CHATWOOT_URL, }, }, }; diff --git a/src/dev-env.yml b/src/dev-env.yml index 85061e12..f51c88b8 100644 --- a/src/dev-env.yml +++ b/src/dev-env.yml @@ -11,7 +11,7 @@ SERVER: CORS: ORIGIN: - - '*' + - "*" # - yourdomain.com METHODS: - POST @@ -63,7 +63,7 @@ CLEAN_STORE: DATABASE: ENABLED: false CONNECTION: - URI: 'mongodb://root:root@localhost:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true' + URI: "mongodb://root:root@localhost:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true" DB_PREFIX_NAME: evolution # Choose the data you want to save in the application's database or store SAVE_DATA: @@ -75,8 +75,8 @@ DATABASE: REDIS: ENABLED: false - URI: 'redis://localhost:6379' - PREFIX_KEY: 'evolution' + URI: "redis://localhost:6379" + PREFIX_KEY: "evolution" # Webhook Settings WEBHOOK: @@ -87,7 +87,7 @@ WEBHOOK: # With this option activated, you work with a url per webhook event, respecting the global url and the name of each event WEBHOOK_BY_EVENTS: false # Automatically maps webhook paths - # Set the events you want to hear + # Set the events you want to hear EVENTS: APPLICATION_STARTUP: false QRCODE_UPDATED: true @@ -112,7 +112,7 @@ WEBHOOK: CONFIG_SESSION_PHONE: # Name that will be displayed on smartphone connection - CLIENT: 'Evolution API' + CLIENT: "Evolution API" NAME: chrome # chrome | firefox | edge | opera | safari # Set qrcode display limit @@ -136,8 +136,11 @@ AUTHENTICATION: SECRET: L=0YWt]b2w[WF>#>:&E` # Set the instance name and webhook url to create an instance in init the application INSTANCE: - # With this option activated, you work with a url per webhook event, respecting the local url and the name of each event + # With this option activated, you work with a url per webhook event, respecting the local url and the name of each event MODE: server # container or server # if you are using container mode, set the container name and the webhook url to default instance NAME: evolution WEBHOOK_URL: + CHATWOOT_ACCOUNT_ID: 1 + CHATWOOT_TOKEN: 123456 + CHATWOOT_URL: diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index 9427b1d7..9b75fd08 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -857,3 +857,16 @@ export const webhookSchema: JSONSchema7 = { required: ['url', 'enabled'], ...isNotEmpty('url'), }; + +export const chatwootSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean', enum: [true, false] }, + account_id: { type: 'string' }, + token: { type: 'string' }, + url: { type: 'string' }, + }, + required: ['enabled', 'account_id', 'token', 'url'], + ...isNotEmpty('account_id', 'token', 'url'), +}; diff --git a/src/whatsapp/controllers/chatwoot.controller.ts b/src/whatsapp/controllers/chatwoot.controller.ts new file mode 100644 index 00000000..c48e9285 --- /dev/null +++ b/src/whatsapp/controllers/chatwoot.controller.ts @@ -0,0 +1,48 @@ +import { isURL } from 'class-validator'; +import { BadRequestException } from '../../exceptions'; +import { InstanceDto } from '../dto/instance.dto'; +import { ChatwootDto } from '../dto/chatwoot.dto'; +import { ChatwootService } from '../services/chatwoot.service'; +import { Logger } from '../../config/logger.config'; + +const logger = new Logger('ChatwootController'); + +export class ChatwootController { + constructor(private readonly chatwootService: ChatwootService) {} + + public async createChatwoot(instance: InstanceDto, data: ChatwootDto) { + logger.verbose( + 'requested createChatwoot from ' + instance.instanceName + ' instance', + ); + + if (data.enabled) { + if (!isURL(data.url, { require_tld: false })) { + throw new BadRequestException('url is not valid'); + } + + if (!data.account_id) { + throw new BadRequestException('account_id is required'); + } + + if (!data.token) { + throw new BadRequestException('token is required'); + } + } + + if (!data.enabled) { + logger.verbose('chatwoot disabled'); + data.account_id = ''; + data.token = ''; + data.url = ''; + } + + data.name_inbox = instance.instanceName; + + return this.chatwootService.create(instance, data); + } + + public async findChatwoot(instance: InstanceDto) { + logger.verbose('requested findChatwoot from ' + instance.instanceName + ' instance'); + return this.chatwootService.find(instance); + } +} diff --git a/src/whatsapp/controllers/instance.controller.ts b/src/whatsapp/controllers/instance.controller.ts index c2abbffa..9ffd7e47 100644 --- a/src/whatsapp/controllers/instance.controller.ts +++ b/src/whatsapp/controllers/instance.controller.ts @@ -8,6 +8,7 @@ import { AuthService, OldToken } from '../services/auth.service'; import { WAMonitoringService } from '../services/monitor.service'; import { WAStartupService } from '../services/whatsapp.service'; import { WebhookService } from '../services/webhook.service'; +import { ChatwootService } from '../services/chatwoot.service'; import { Logger } from '../../config/logger.config'; import { wa } from '../types/wa.types'; import { RedisCache } from '../../db/redis.client'; @@ -20,6 +21,7 @@ export class InstanceController { private readonly eventEmitter: EventEmitter2, private readonly authService: AuthService, private readonly webhookService: WebhookService, + private readonly chatwootService: ChatwootService, private readonly cache: RedisCache, ) {} @@ -32,6 +34,9 @@ export class InstanceController { events, qrcode, token, + chatwoot_account_id, + chatwoot_token, + chatwoot_url, }: InstanceDto) { this.logger.verbose('requested createInstance from ' + instanceName + ' instance'); @@ -73,34 +78,70 @@ export class InstanceController { this.logger.verbose('hash: ' + hash + ' generated'); - let getEvents: string[]; + if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) { + let getEvents: string[]; - if (webhook) { - this.logger.verbose('creating webhook'); - try { - this.webhookService.create(instance, { - enabled: true, - url: webhook, - events, - webhook_by_events, - }); + if (webhook) { + this.logger.verbose('creating webhook'); + try { + this.webhookService.create(instance, { + enabled: true, + url: webhook, + events, + webhook_by_events, + }); - getEvents = (await this.webhookService.find(instance)).events; - } catch (error) { - this.logger.log(error); + getEvents = (await this.webhookService.find(instance)).events; + } catch (error) { + this.logger.log(error); + } } + + this.logger.verbose('instance created'); + this.logger.verbose({ + instance: { + instanceName: instance.instanceName, + status: 'created', + }, + hash, + webhook, + events: getEvents, + }); + + return { + instance: { + instanceName: instance.instanceName, + status: 'created', + }, + hash, + webhook, + events: getEvents, + }; } - this.logger.verbose('instance created'); - this.logger.verbose({ - instance: { - instanceName: instance.instanceName, - status: 'created', - }, - hash, - webhook, - events: getEvents, - }); + if (!chatwoot_account_id) { + throw new BadRequestException('account_id is required'); + } + + if (!chatwoot_token) { + throw new BadRequestException('token is required'); + } + + if (!chatwoot_url) { + throw new BadRequestException('url is required'); + } + + try { + this.chatwootService.create(instance, { + enabled: true, + account_id: chatwoot_account_id, + token: chatwoot_token, + url: chatwoot_url, + name_inbox: instance.instanceName, + }); + } catch (error) { + this.logger.log(error); + } return { instance: { @@ -108,8 +149,13 @@ export class InstanceController { status: 'created', }, hash, - webhook, - events: getEvents, + chatwoot: { + enabled: true, + account_id: chatwoot_account_id, + token: chatwoot_token, + url: chatwoot_url, + name_inbox: instance.instanceName, + }, }; } else { this.logger.verbose('server mode'); @@ -141,45 +187,83 @@ export class InstanceController { this.logger.verbose('hash: ' + hash + ' generated'); - let getEvents: string[]; + if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) { + let getEvents: string[]; - if (webhook) { - this.logger.verbose('creating webhook'); - try { - this.webhookService.create(instance, { - enabled: true, - url: webhook, - events, - webhook_by_events, - }); + if (webhook) { + this.logger.verbose('creating webhook'); + try { + this.webhookService.create(instance, { + enabled: true, + url: webhook, + events, + webhook_by_events, + }); - getEvents = (await this.webhookService.find(instance)).events; - } catch (error) { - this.logger.log(error); + getEvents = (await this.webhookService.find(instance)).events; + } catch (error) { + this.logger.log(error); + } } + + let getQrcode: wa.QrCode; + + if (qrcode) { + this.logger.verbose('creating qrcode'); + await instance.connectToWhatsapp(); + await delay(2000); + getQrcode = instance.qrCode; + } + + this.logger.verbose('instance created'); + this.logger.verbose({ + instance: { + instanceName: instance.instanceName, + status: 'created', + }, + hash, + webhook, + webhook_by_events, + events: getEvents, + qrcode: getQrcode, + }); + + return { + instance: { + instanceName: instance.instanceName, + status: 'created', + }, + hash, + webhook, + webhook_by_events, + events: getEvents, + qrcode: getQrcode, + }; } - let getQrcode: wa.QrCode; - - if (qrcode) { - this.logger.verbose('creating qrcode'); - await instance.connectToWhatsapp(); - await delay(2000); - getQrcode = instance.qrCode; + if (!chatwoot_account_id) { + throw new BadRequestException('account_id is required'); } - this.logger.verbose('instance created'); - this.logger.verbose({ - instance: { - instanceName: instance.instanceName, - status: 'created', - }, - hash, - webhook, - webhook_by_events, - events: getEvents, - qrcode: getQrcode, - }); + if (!chatwoot_token) { + throw new BadRequestException('token is required'); + } + + if (!chatwoot_url) { + throw new BadRequestException('url is required'); + } + + try { + this.chatwootService.create(instance, { + enabled: true, + account_id: chatwoot_account_id, + token: chatwoot_token, + url: chatwoot_url, + name_inbox: instance.instanceName, + }); + } catch (error) { + this.logger.log(error); + } return { instance: { @@ -187,10 +271,13 @@ export class InstanceController { status: 'created', }, hash, - webhook, - webhook_by_events, - events: getEvents, - qrcode: getQrcode, + chatwoot: { + enabled: true, + account_id: chatwoot_account_id, + token: chatwoot_token, + url: chatwoot_url, + name_inbox: instance.instanceName, + }, }; } } diff --git a/src/whatsapp/dto/chatwoot.dto.ts b/src/whatsapp/dto/chatwoot.dto.ts new file mode 100644 index 00000000..a65bbf71 --- /dev/null +++ b/src/whatsapp/dto/chatwoot.dto.ts @@ -0,0 +1,7 @@ +export class ChatwootDto { + enabled?: boolean; + account_id?: string; + token?: string; + url?: string; + name_inbox?: string; +} diff --git a/src/whatsapp/dto/instance.dto.ts b/src/whatsapp/dto/instance.dto.ts index 8a3902e9..479a1dae 100644 --- a/src/whatsapp/dto/instance.dto.ts +++ b/src/whatsapp/dto/instance.dto.ts @@ -5,4 +5,7 @@ export class InstanceDto { events?: string[]; qrcode?: boolean; token?: string; + chatwoot_account_id?: string; + chatwoot_token?: string; + chatwoot_url?: string; } diff --git a/src/whatsapp/models/chatwoot.model.ts b/src/whatsapp/models/chatwoot.model.ts new file mode 100644 index 00000000..cb298c91 --- /dev/null +++ b/src/whatsapp/models/chatwoot.model.ts @@ -0,0 +1,25 @@ +import { Schema } from 'mongoose'; +import { dbserver } from '../../db/db.connect'; + +export class ChatwootRaw { + _id?: string; + account_id?: string; + token?: string; + url?: string; + name_inbox?: string; +} + +const chatwootSchema = new Schema({ + _id: { type: String, _id: true }, + account_id: { type: String, required: true }, + token: { type: String, required: true }, + url: { type: String, required: true }, + name_inbox: { type: String, required: true }, +}); + +export const ChatwootModel = dbserver?.model( + ChatwootRaw.name, + chatwootSchema, + 'chatwoot', +); +export type IChatwootModel = typeof ChatwootModel; diff --git a/src/whatsapp/models/index.ts b/src/whatsapp/models/index.ts index 11f760d9..e0b773f0 100644 --- a/src/whatsapp/models/index.ts +++ b/src/whatsapp/models/index.ts @@ -3,3 +3,4 @@ export * from './contact.model'; export * from './message.model'; export * from './auth.model'; export * from './webhook.model'; +export * from './chatwoot.model'; diff --git a/src/whatsapp/repository/chatwoot.repository.ts b/src/whatsapp/repository/chatwoot.repository.ts new file mode 100644 index 00000000..3d24022a --- /dev/null +++ b/src/whatsapp/repository/chatwoot.repository.ts @@ -0,0 +1,75 @@ +import { IInsert, Repository } from '../abstract/abstract.repository'; +import { ConfigService } from '../../config/env.config'; +import { join } from 'path'; +import { readFileSync } from 'fs'; +import { IChatwootModel, ChatwootRaw } from '../models'; +import { Logger } from '../../config/logger.config'; + +export class ChatwootRepository extends Repository { + constructor( + private readonly chatwootModel: IChatwootModel, + private readonly configService: ConfigService, + ) { + super(configService); + } + + private readonly logger = new Logger('ChatwootRepository'); + + public async create(data: ChatwootRaw, instance: string): Promise { + try { + this.logger.verbose('creating chatwoot'); + if (this.dbSettings.ENABLED) { + this.logger.verbose('saving chatwoot to db'); + const insert = await this.chatwootModel.replaceOne( + { _id: instance }, + { ...data }, + { upsert: true }, + ); + + this.logger.verbose( + 'chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot', + ); + return { insertCount: insert.modifiedCount }; + } + + this.logger.verbose('saving chatwoot to store'); + + this.writeStore({ + path: join(this.storePath, 'chatwoot'), + fileName: instance, + data, + }); + + this.logger.verbose( + 'chatwoot saved to store in path: ' + + join(this.storePath, 'chatwoot') + + '/' + + instance, + ); + + this.logger.verbose('chatwoot created'); + return { insertCount: 1 }; + } catch (error) { + return error; + } + } + + public async find(instance: string): Promise { + try { + this.logger.verbose('finding chatwoot'); + if (this.dbSettings.ENABLED) { + this.logger.verbose('finding chatwoot in db'); + return await this.chatwootModel.findOne({ _id: instance }); + } + + this.logger.verbose('finding chatwoot in store'); + return JSON.parse( + readFileSync(join(this.storePath, 'chatwoot', instance + '.json'), { + encoding: 'utf-8', + }), + ) as ChatwootRaw; + } catch (error) { + return {}; + } + } +} diff --git a/src/whatsapp/repository/repository.manager.ts b/src/whatsapp/repository/repository.manager.ts index bd41e09e..9740b436 100644 --- a/src/whatsapp/repository/repository.manager.ts +++ b/src/whatsapp/repository/repository.manager.ts @@ -4,6 +4,7 @@ import { ContactRepository } from './contact.repository'; import { MessageUpRepository } from './messageUp.repository'; import { MongoClient } from 'mongodb'; import { WebhookRepository } from './webhook.repository'; +import { ChatwootRepository } from './chatwoot.repository'; import { AuthRepository } from './auth.repository'; import { Auth, ConfigService, Database } from '../../config/env.config'; import { execSync } from 'child_process'; @@ -17,6 +18,7 @@ export class RepositoryBroker { public readonly contact: ContactRepository, public readonly messageUpdate: MessageUpRepository, public readonly webhook: WebhookRepository, + public readonly chatwoot: ChatwootRepository, public readonly auth: AuthRepository, private configService: ConfigService, dbServer?: MongoClient, @@ -64,6 +66,9 @@ export class RepositoryBroker { this.logger.verbose('creating webhook path: ' + join(storePath, 'webhook')); execSync(`mkdir -p ${join(storePath, 'webhook')}`); + this.logger.verbose('creating chatwoot path: ' + join(storePath, 'chatwoot')); + execSync(`mkdir -p ${join(storePath, 'chatwoot')}`); + this.logger.verbose('creating temp path: ' + join(storePath, 'temp')); execSync(`mkdir -p ${join(storePath, 'temp')}`); } diff --git a/src/whatsapp/routers/chatwoot.router.ts b/src/whatsapp/routers/chatwoot.router.ts new file mode 100644 index 00000000..e2030304 --- /dev/null +++ b/src/whatsapp/routers/chatwoot.router.ts @@ -0,0 +1,51 @@ +import { RequestHandler, Router } from 'express'; +import { instanceNameSchema, chatwootSchema } from '../../validate/validate.schema'; +import { RouterBroker } from '../abstract/abstract.router'; +import { InstanceDto } from '../dto/instance.dto'; +import { ChatwootDto } from '../dto/chatwoot.dto'; +import { chatwootController } from '../whatsapp.module'; +import { HttpStatus } from './index.router'; +import { Logger } from '../../config/logger.config'; + +const logger = new Logger('ChatwootRouter'); + +export class ChatwootRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('set'), ...guards, async (req, res) => { + logger.verbose('request received in setChatwoot'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: chatwootSchema, + ClassRef: ChatwootDto, + execute: (instance, data) => chatwootController.createChatwoot(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + logger.verbose('request received in findChatwoot'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: instanceNameSchema, + ClassRef: InstanceDto, + execute: (instance) => chatwootController.findChatwoot(instance), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router = Router(); +} diff --git a/src/whatsapp/routers/index.router.ts b/src/whatsapp/routers/index.router.ts index 80f23c41..c25d320e 100644 --- a/src/whatsapp/routers/index.router.ts +++ b/src/whatsapp/routers/index.router.ts @@ -8,6 +8,7 @@ import { InstanceRouter } from './instance.router'; import { MessageRouter } from './sendMessage.router'; import { ViewsRouter } from './view.router'; import { WebhookRouter } from './webhook.router'; +import { ChatwootRouter } from './chatwoot.router'; enum HttpStatus { OK = 200, @@ -32,6 +33,7 @@ router .use('/message', new MessageRouter(...guards).router) .use('/chat', new ChatRouter(...guards).router) .use('/group', new GroupRouter(...guards).router) - .use('/webhook', new WebhookRouter(...guards).router); + .use('/webhook', new WebhookRouter(...guards).router) + .use('/chatwoot', new ChatwootRouter(...guards).router); export { router, HttpStatus }; diff --git a/src/whatsapp/services/chatwoot.service.ts b/src/whatsapp/services/chatwoot.service.ts new file mode 100644 index 00000000..74ea9eea --- /dev/null +++ b/src/whatsapp/services/chatwoot.service.ts @@ -0,0 +1,26 @@ +import { InstanceDto } from '../dto/instance.dto'; +import { ChatwootDto } from '../dto/chatwoot.dto'; +import { WAMonitoringService } from './monitor.service'; +import { Logger } from '../../config/logger.config'; + +export class ChatwootService { + constructor(private readonly waMonitor: WAMonitoringService) {} + + private readonly logger = new Logger(ChatwootService.name); + + public create(instance: InstanceDto, data: ChatwootDto) { + this.logger.verbose('create chatwoot: ' + instance.instanceName); + this.waMonitor.waInstances[instance.instanceName].setChatwoot(data); + + return { chatwoot: { ...instance, chatwoot: data } }; + } + + public async find(instance: InstanceDto): Promise { + try { + this.logger.verbose('find chatwoot: ' + instance.instanceName); + return await this.waMonitor.waInstances[instance.instanceName].findChatwoot(); + } catch (error) { + return { enabled: null, url: '' }; + } + } +} diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index e2486e69..f7da72ef 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -114,6 +114,7 @@ import { MessageUpQuery } from '../repository/messageUp.repository'; import { useMultiFileAuthStateDb } from '../../utils/use-multi-file-auth-state-db'; import Long from 'long'; import { WebhookRaw } from '../models/webhook.model'; +import { ChatwootRaw } from '../models/chatwoot.model'; import { dbserver } from '../../db/db.connect'; import NodeCache from 'node-cache'; import { useMultiFileAuthStateRedisDb } from '../../utils/use-multi-file-auth-state-redis-db'; @@ -138,6 +139,7 @@ export class WAStartupService { private readonly instance: wa.Instance = {}; public client: WASocket; private readonly localWebhook: wa.LocalWebHook = {}; + private readonly localChatwoot: wa.LocalChatwoot = {}; private stateConnection: wa.StateConnection = { state: 'close' }; private readonly storePath = join(ROOT_DIR, 'store'); private readonly msgRetryCounterCache: CacheStore = new NodeCache(); @@ -268,6 +270,34 @@ export class WAStartupService { return data; } + public async setChatwoot(data: ChatwootRaw) { + this.logger.verbose('Setting chatwoot'); + await this.repository.chatwoot.create(data, this.instanceName); + this.logger.verbose(`Chatwoot account id: ${data.account_id}`); + this.logger.verbose(`Chatwoot token: ${data.token}`); + this.logger.verbose(`Chatwoot url: ${data.url}`); + this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`); + + Object.assign(this.localChatwoot, data); + this.logger.verbose('Chatwoot set'); + } + + public async findChatwoot() { + this.logger.verbose('Finding chatwoot'); + const data = await this.repository.chatwoot.find(this.instanceName); + + if (!data) { + this.logger.verbose('Chatwoot not found'); + throw new NotFoundException('Chatwoot not found'); + } + + this.logger.verbose(`Chatwoot account id: ${data.account_id}`); + this.logger.verbose(`Chatwoot token: ${data.token}`); + this.logger.verbose(`Chatwoot url: ${data.url}`); + this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`); + return data; + } + public async sendDataWebhook(event: Events, data: T, local = true) { const webhookGlobal = this.configService.get('WEBHOOK'); const webhookLocal = this.localWebhook.events; diff --git a/src/whatsapp/types/wa.types.ts b/src/whatsapp/types/wa.types.ts index 1686f031..e08aef78 100644 --- a/src/whatsapp/types/wa.types.ts +++ b/src/whatsapp/types/wa.types.ts @@ -41,6 +41,14 @@ export declare namespace wa { webhook_by_events?: boolean; }; + export type LocalChatwoot = { + enabled?: boolean; + account_id?: string; + token?: string; + url?: string; + name_inbox?: string; + }; + export type StateConnection = { instance?: string; state?: WAConnectionState | 'refused'; diff --git a/src/whatsapp/whatsapp.module.ts b/src/whatsapp/whatsapp.module.ts index f05b8323..a03ca18d 100644 --- a/src/whatsapp/whatsapp.module.ts +++ b/src/whatsapp/whatsapp.module.ts @@ -14,6 +14,8 @@ import { GroupController } from './controllers/group.controller'; import { ViewsController } from './controllers/views.controller'; import { WebhookService } from './services/webhook.service'; import { WebhookController } from './controllers/webhook.controller'; +import { ChatwootService } from './services/chatwoot.service'; +import { ChatwootController } from './controllers/chatwoot.controller'; import { RepositoryBroker } from './repository/repository.manager'; import { AuthModel, @@ -21,10 +23,12 @@ import { ContactModel, MessageModel, MessageUpModel, + ChatwootModel, + WebhookModel, } from './models'; import { dbserver } from '../db/db.connect'; import { WebhookRepository } from './repository/webhook.repository'; -import { WebhookModel } from './models/webhook.model'; +import { ChatwootRepository } from './repository/chatwoot.repository'; import { AuthRepository } from './repository/auth.repository'; import { WAStartupService } from './services/whatsapp.service'; import { delay } from '@whiskeysockets/baileys'; @@ -38,6 +42,7 @@ const chatRepository = new ChatRepository(ChatModel, configService); const contactRepository = new ContactRepository(ContactModel, configService); const messageUpdateRepository = new MessageUpRepository(MessageUpModel, configService); const webhookRepository = new WebhookRepository(WebhookModel, configService); +const chatwootRepository = new ChatwootRepository(ChatwootModel, configService); const authRepository = new AuthRepository(AuthModel, configService); export const repository = new RepositoryBroker( @@ -46,6 +51,7 @@ export const repository = new RepositoryBroker( contactRepository, messageUpdateRepository, webhookRepository, + chatwootRepository, authRepository, configService, dbserver?.getClient(), @@ -66,6 +72,10 @@ const webhookService = new WebhookService(waMonitor); export const webhookController = new WebhookController(webhookService); +const chatwootService = new ChatwootService(waMonitor); + +export const chatwootController = new ChatwootController(chatwootService); + export const instanceController = new InstanceController( waMonitor, configService, @@ -73,6 +83,7 @@ export const instanceController = new InstanceController( eventEmitter, authService, webhookService, + chatwootService, cache, ); export const viewsController = new ViewsController(waMonitor, configService);