mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-16 04:02:54 -06:00
Implementation of Whatsapp labels management
This commit is contained in:
parent
32026d1fd4
commit
23f1b4ac03
@ -7,6 +7,7 @@
|
|||||||
* Join in Group by Invite Code
|
* Join in Group by Invite Code
|
||||||
* Read messages from whatsapp in chatwoot
|
* Read messages from whatsapp in chatwoot
|
||||||
* Add support to use use redis in cacheservice
|
* Add support to use use redis in cacheservice
|
||||||
|
* Add support for labels
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -84,6 +84,8 @@ WEBHOOK_EVENTS_GROUPS_UPSERT=true
|
|||||||
WEBHOOK_EVENTS_GROUPS_UPDATE=true
|
WEBHOOK_EVENTS_GROUPS_UPDATE=true
|
||||||
WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
|
WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
|
||||||
WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
||||||
|
WEBHOOK_EVENTS_LABELS_EDIT=true
|
||||||
|
WEBHOOK_EVENTS_LABELS_ASSOCIATION=true
|
||||||
WEBHOOK_EVENTS_CALL=true
|
WEBHOOK_EVENTS_CALL=true
|
||||||
# This event fires every time a new token is requested via the refresh route
|
# This event fires every time a new token is requested via the refresh route
|
||||||
WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
|
WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
|
||||||
|
@ -73,6 +73,8 @@ WEBHOOK_EVENTS_GROUPS_UPSERT=true
|
|||||||
WEBHOOK_EVENTS_GROUPS_UPDATE=true
|
WEBHOOK_EVENTS_GROUPS_UPDATE=true
|
||||||
WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
|
WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
|
||||||
WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
||||||
|
WEBHOOK_EVENTS_LABELS_EDIT=true
|
||||||
|
WEBHOOK_EVENTS_LABELS_ASSOCIATION=true
|
||||||
# This event fires every time a new token is requested via the refresh route
|
# This event fires every time a new token is requested via the refresh route
|
||||||
WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
|
WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
|
||||||
|
|
||||||
|
@ -98,6 +98,8 @@ ENV WEBHOOK_EVENTS_GROUPS_UPSERT=true
|
|||||||
ENV WEBHOOK_EVENTS_GROUPS_UPDATE=true
|
ENV WEBHOOK_EVENTS_GROUPS_UPDATE=true
|
||||||
ENV WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
|
ENV WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
|
||||||
ENV WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
ENV WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
||||||
|
ENV WEBHOOK_EVENTS_LABELS_EDIT=true
|
||||||
|
ENV WEBHOOK_EVENTS_LABELS_ASSOCIATION=true
|
||||||
ENV WEBHOOK_EVENTS_CALL=true
|
ENV WEBHOOK_EVENTS_CALL=true
|
||||||
|
|
||||||
ENV WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
|
ENV WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
|
||||||
|
@ -34,6 +34,7 @@ export type SaveData = {
|
|||||||
MESSAGE_UPDATE: boolean;
|
MESSAGE_UPDATE: boolean;
|
||||||
CONTACTS: boolean;
|
CONTACTS: boolean;
|
||||||
CHATS: boolean;
|
CHATS: boolean;
|
||||||
|
LABELS: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StoreConf = {
|
export type StoreConf = {
|
||||||
@ -41,6 +42,7 @@ export type StoreConf = {
|
|||||||
MESSAGE_UP: boolean;
|
MESSAGE_UP: boolean;
|
||||||
CONTACTS: boolean;
|
CONTACTS: boolean;
|
||||||
CHATS: boolean;
|
CHATS: boolean;
|
||||||
|
LABELS: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CleanStoreConf = {
|
export type CleanStoreConf = {
|
||||||
@ -103,6 +105,8 @@ export type EventsWebhook = {
|
|||||||
CHATS_DELETE: boolean;
|
CHATS_DELETE: boolean;
|
||||||
CHATS_UPSERT: boolean;
|
CHATS_UPSERT: boolean;
|
||||||
CONNECTION_UPDATE: boolean;
|
CONNECTION_UPDATE: boolean;
|
||||||
|
LABELS_EDIT: boolean;
|
||||||
|
LABELS_ASSOCIATION: boolean;
|
||||||
GROUPS_UPSERT: boolean;
|
GROUPS_UPSERT: boolean;
|
||||||
GROUP_UPDATE: boolean;
|
GROUP_UPDATE: boolean;
|
||||||
GROUP_PARTICIPANTS_UPDATE: boolean;
|
GROUP_PARTICIPANTS_UPDATE: boolean;
|
||||||
@ -237,6 +241,7 @@ export class ConfigService {
|
|||||||
MESSAGE_UP: process.env?.STORE_MESSAGE_UP === 'true',
|
MESSAGE_UP: process.env?.STORE_MESSAGE_UP === 'true',
|
||||||
CONTACTS: process.env?.STORE_CONTACTS === 'true',
|
CONTACTS: process.env?.STORE_CONTACTS === 'true',
|
||||||
CHATS: process.env?.STORE_CHATS === 'true',
|
CHATS: process.env?.STORE_CHATS === 'true',
|
||||||
|
LABELS: process.env?.STORE_LABELS === 'true',
|
||||||
},
|
},
|
||||||
CLEAN_STORE: {
|
CLEAN_STORE: {
|
||||||
CLEANING_INTERVAL: Number.isInteger(process.env?.CLEAN_STORE_CLEANING_TERMINAL)
|
CLEANING_INTERVAL: Number.isInteger(process.env?.CLEAN_STORE_CLEANING_TERMINAL)
|
||||||
@ -259,6 +264,7 @@ export class ConfigService {
|
|||||||
MESSAGE_UPDATE: process.env?.DATABASE_SAVE_MESSAGE_UPDATE === 'true',
|
MESSAGE_UPDATE: process.env?.DATABASE_SAVE_MESSAGE_UPDATE === 'true',
|
||||||
CONTACTS: process.env?.DATABASE_SAVE_DATA_CONTACTS === 'true',
|
CONTACTS: process.env?.DATABASE_SAVE_DATA_CONTACTS === 'true',
|
||||||
CHATS: process.env?.DATABASE_SAVE_DATA_CHATS === 'true',
|
CHATS: process.env?.DATABASE_SAVE_DATA_CHATS === 'true',
|
||||||
|
LABELS: process.env?.DATABASE_SAVE_DATA_LABELS === 'true',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
REDIS: {
|
REDIS: {
|
||||||
@ -323,6 +329,8 @@ export class ConfigService {
|
|||||||
CHATS_UPSERT: process.env?.WEBHOOK_EVENTS_CHATS_UPSERT === 'true',
|
CHATS_UPSERT: process.env?.WEBHOOK_EVENTS_CHATS_UPSERT === 'true',
|
||||||
CHATS_DELETE: process.env?.WEBHOOK_EVENTS_CHATS_DELETE === 'true',
|
CHATS_DELETE: process.env?.WEBHOOK_EVENTS_CHATS_DELETE === 'true',
|
||||||
CONNECTION_UPDATE: process.env?.WEBHOOK_EVENTS_CONNECTION_UPDATE === 'true',
|
CONNECTION_UPDATE: process.env?.WEBHOOK_EVENTS_CONNECTION_UPDATE === 'true',
|
||||||
|
LABELS_EDIT: process.env?.WEBHOOK_EVENTS_LABELS_EDIT === 'true',
|
||||||
|
LABELS_ASSOCIATION: process.env?.WEBHOOK_EVENTS_LABELS_ASSOCIATION === 'true',
|
||||||
GROUPS_UPSERT: process.env?.WEBHOOK_EVENTS_GROUPS_UPSERT === 'true',
|
GROUPS_UPSERT: process.env?.WEBHOOK_EVENTS_GROUPS_UPSERT === 'true',
|
||||||
GROUP_UPDATE: process.env?.WEBHOOK_EVENTS_GROUPS_UPDATE === 'true',
|
GROUP_UPDATE: process.env?.WEBHOOK_EVENTS_GROUPS_UPDATE === 'true',
|
||||||
GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true',
|
GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true',
|
||||||
|
@ -127,6 +127,8 @@ WEBHOOK:
|
|||||||
GROUP_UPDATE: true
|
GROUP_UPDATE: true
|
||||||
GROUP_PARTICIPANTS_UPDATE: true
|
GROUP_PARTICIPANTS_UPDATE: true
|
||||||
CONNECTION_UPDATE: true
|
CONNECTION_UPDATE: true
|
||||||
|
LABELS_EDIT: true
|
||||||
|
LABELS_ASSOCIATION: true
|
||||||
CALL: true
|
CALL: true
|
||||||
# This event fires every time a new token is requested via the refresh route
|
# This event fires every time a new token is requested via the refresh route
|
||||||
NEW_JWT_TOKEN: false
|
NEW_JWT_TOKEN: false
|
||||||
|
@ -51,6 +51,7 @@ tags:
|
|||||||
- name: Send Message Controller
|
- name: Send Message Controller
|
||||||
- name: Chat Controller
|
- name: Chat Controller
|
||||||
- name: Group Controller
|
- name: Group Controller
|
||||||
|
- name: Label Controller
|
||||||
- name: Profile Settings
|
- name: Profile Settings
|
||||||
- name: JWT
|
- name: JWT
|
||||||
- name: Settings
|
- name: Settings
|
||||||
@ -1856,6 +1857,8 @@ paths:
|
|||||||
"GROUP_UPDATE",
|
"GROUP_UPDATE",
|
||||||
"GROUP_PARTICIPANTS_UPDATE",
|
"GROUP_PARTICIPANTS_UPDATE",
|
||||||
"CONNECTION_UPDATE",
|
"CONNECTION_UPDATE",
|
||||||
|
"LABELS_EDIT",
|
||||||
|
"LABELS_ASSOCIATION",
|
||||||
"CALL",
|
"CALL",
|
||||||
"NEW_JWT_TOKEN",
|
"NEW_JWT_TOKEN",
|
||||||
]
|
]
|
||||||
@ -1932,6 +1935,8 @@ paths:
|
|||||||
"GROUP_UPDATE",
|
"GROUP_UPDATE",
|
||||||
"GROUP_PARTICIPANTS_UPDATE",
|
"GROUP_PARTICIPANTS_UPDATE",
|
||||||
"CONNECTION_UPDATE",
|
"CONNECTION_UPDATE",
|
||||||
|
"LABELS_EDIT",
|
||||||
|
"LABELS_ASSOCIATION",
|
||||||
"CALL",
|
"CALL",
|
||||||
"NEW_JWT_TOKEN",
|
"NEW_JWT_TOKEN",
|
||||||
]
|
]
|
||||||
@ -2008,6 +2013,8 @@ paths:
|
|||||||
"GROUP_UPDATE",
|
"GROUP_UPDATE",
|
||||||
"GROUP_PARTICIPANTS_UPDATE",
|
"GROUP_PARTICIPANTS_UPDATE",
|
||||||
"CONNECTION_UPDATE",
|
"CONNECTION_UPDATE",
|
||||||
|
"LABELS_EDIT",
|
||||||
|
"LABELS_ASSOCIATION",
|
||||||
"CALL",
|
"CALL",
|
||||||
"NEW_JWT_TOKEN",
|
"NEW_JWT_TOKEN",
|
||||||
]
|
]
|
||||||
@ -2046,6 +2053,96 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json: {}
|
application/json: {}
|
||||||
|
|
||||||
|
/label/findLabels/{instanceName}:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Label Controller
|
||||||
|
summary: List all labels for an instance.
|
||||||
|
parameters:
|
||||||
|
- name: instanceName
|
||||||
|
in: path
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
description: "- required"
|
||||||
|
example: "evolution"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful response
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
color:
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
predefinedId:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- color
|
||||||
|
- name
|
||||||
|
- id
|
||||||
|
/label/handleLabel/{instanceName}:
|
||||||
|
put:
|
||||||
|
tags:
|
||||||
|
- Label Controller
|
||||||
|
summary: Change the label (add or remove) for an specific chat.
|
||||||
|
parameters:
|
||||||
|
- name: instanceName
|
||||||
|
in: path
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
description: "- required"
|
||||||
|
example: "evolution"
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
number:
|
||||||
|
type: string
|
||||||
|
labelId:
|
||||||
|
type: string
|
||||||
|
action:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- add
|
||||||
|
- remove
|
||||||
|
required:
|
||||||
|
- number
|
||||||
|
- labelId
|
||||||
|
- action
|
||||||
|
example:
|
||||||
|
number: '553499999999'
|
||||||
|
labelId: '1'
|
||||||
|
action: add
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful response
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
numberJid:
|
||||||
|
type: string
|
||||||
|
labelId:
|
||||||
|
type: string
|
||||||
|
remove:
|
||||||
|
type: boolean
|
||||||
|
required:
|
||||||
|
- numberJid
|
||||||
|
- labelId
|
||||||
|
- remove
|
||||||
|
|
||||||
/settings/set/{instanceName}:
|
/settings/set/{instanceName}:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
|
@ -53,6 +53,8 @@ export const instanceNameSchema: JSONSchema7 = {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
@ -897,6 +899,8 @@ export const webhookSchema: JSONSchema7 = {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
@ -977,6 +981,8 @@ export const websocketSchema: JSONSchema7 = {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
@ -1020,6 +1026,8 @@ export const rabbitmqSchema: JSONSchema7 = {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
@ -1063,6 +1071,8 @@ export const sqsSchema: JSONSchema7 = {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
@ -1150,3 +1160,14 @@ export const chamaaiSchema: JSONSchema7 = {
|
|||||||
required: ['enabled', 'url', 'token', 'waNumber', 'answerByAudio'],
|
required: ['enabled', 'url', 'token', 'waNumber', 'answerByAudio'],
|
||||||
...isNotEmpty('enabled', 'url', 'token', 'waNumber', 'answerByAudio'),
|
...isNotEmpty('enabled', 'url', 'token', 'waNumber', 'answerByAudio'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const handleLabelSchema: JSONSchema7 = {
|
||||||
|
$id: v4(),
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
number: { ...numberDefinition },
|
||||||
|
labelId: { type: 'string' },
|
||||||
|
action: { type: 'string', enum: ['add', 'remove'] },
|
||||||
|
},
|
||||||
|
required: ['number', 'labelId', 'action'],
|
||||||
|
};
|
||||||
|
@ -151,6 +151,8 @@ export class InstanceController {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
@ -201,6 +203,8 @@ export class InstanceController {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
@ -248,6 +252,8 @@ export class InstanceController {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
@ -295,6 +301,8 @@ export class InstanceController {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
|
20
src/whatsapp/controllers/label.controller.ts
Normal file
20
src/whatsapp/controllers/label.controller.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { HandleLabelDto } from '../dto/label.dto';
|
||||||
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
|
|
||||||
|
const logger = new Logger('LabelController');
|
||||||
|
|
||||||
|
export class LabelController {
|
||||||
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
|
|
||||||
|
public async fetchLabels({ instanceName }: InstanceDto) {
|
||||||
|
logger.verbose('requested fetchLabels from ' + instanceName + ' instance');
|
||||||
|
return await this.waMonitor.waInstances[instanceName].fetchLabels();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleLabel({ instanceName }: InstanceDto, data: HandleLabelDto) {
|
||||||
|
logger.verbose('requested chat label change from ' + instanceName + ' instance');
|
||||||
|
return await this.waMonitor.waInstances[instanceName].handleLabel(data);
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,8 @@ export class RabbitmqController {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
|
@ -38,6 +38,8 @@ export class SqsController {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
|
@ -46,6 +46,8 @@ export class WebhookController {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
|
@ -38,6 +38,8 @@ export class WebsocketController {
|
|||||||
'GROUP_UPDATE',
|
'GROUP_UPDATE',
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
'CONNECTION_UPDATE',
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
'CALL',
|
'CALL',
|
||||||
'NEW_JWT_TOKEN',
|
'NEW_JWT_TOKEN',
|
||||||
'TYPEBOT_START',
|
'TYPEBOT_START',
|
||||||
|
121
src/whatsapp/dto/label.dto.ts
Normal file
121
src/whatsapp/dto/label.dto.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import { proto, WAPresence, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys';
|
||||||
|
|
||||||
|
export class OnWhatsAppDto {
|
||||||
|
constructor(
|
||||||
|
public readonly jid: string,
|
||||||
|
public readonly exists: boolean,
|
||||||
|
public readonly number: string,
|
||||||
|
public readonly name?: string,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LabelDto {
|
||||||
|
id?: string;
|
||||||
|
name: string;
|
||||||
|
color: number;
|
||||||
|
predefinedId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HandleLabelDto {
|
||||||
|
number: string;
|
||||||
|
labelId: string;
|
||||||
|
action: 'add' | 'remove';
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WhatsAppNumberDto {
|
||||||
|
numbers: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NumberDto {
|
||||||
|
number: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NumberBusiness {
|
||||||
|
wid?: string;
|
||||||
|
jid?: string;
|
||||||
|
exists?: boolean;
|
||||||
|
isBusiness: boolean;
|
||||||
|
name?: string;
|
||||||
|
message?: string;
|
||||||
|
description?: string;
|
||||||
|
email?: string;
|
||||||
|
website?: string[];
|
||||||
|
address?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ProfileNameDto {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ProfileStatusDto {
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ProfilePictureDto {
|
||||||
|
number?: string;
|
||||||
|
// url or base64
|
||||||
|
picture?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Key {
|
||||||
|
id: string;
|
||||||
|
fromMe: boolean;
|
||||||
|
remoteJid: string;
|
||||||
|
}
|
||||||
|
export class ReadMessageDto {
|
||||||
|
read_messages: Key[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LastMessage {
|
||||||
|
key: Key;
|
||||||
|
messageTimestamp?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ArchiveChatDto {
|
||||||
|
lastMessage?: LastMessage;
|
||||||
|
chat?: string;
|
||||||
|
archive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrivacySetting {
|
||||||
|
readreceipts: WAReadReceiptsValue;
|
||||||
|
profile: WAPrivacyValue;
|
||||||
|
status: WAPrivacyValue;
|
||||||
|
online: WAPrivacyOnlineValue;
|
||||||
|
last: WAPrivacyValue;
|
||||||
|
groupadd: WAPrivacyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PrivacySettingDto {
|
||||||
|
privacySettings: PrivacySetting;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DeleteMessage {
|
||||||
|
id: string;
|
||||||
|
fromMe: boolean;
|
||||||
|
remoteJid: string;
|
||||||
|
participant?: string;
|
||||||
|
}
|
||||||
|
export class Options {
|
||||||
|
delay?: number;
|
||||||
|
presence?: WAPresence;
|
||||||
|
}
|
||||||
|
class OptionsMessage {
|
||||||
|
options: Options;
|
||||||
|
}
|
||||||
|
export class Metadata extends OptionsMessage {
|
||||||
|
number: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SendPresenceDto extends Metadata {
|
||||||
|
options: {
|
||||||
|
presence: WAPresence;
|
||||||
|
delay: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateMessageDto extends Metadata {
|
||||||
|
number: string;
|
||||||
|
key: proto.IMessageKey;
|
||||||
|
text: string;
|
||||||
|
}
|
@ -3,6 +3,7 @@ export * from './chamaai.model';
|
|||||||
export * from './chat.model';
|
export * from './chat.model';
|
||||||
export * from './chatwoot.model';
|
export * from './chatwoot.model';
|
||||||
export * from './contact.model';
|
export * from './contact.model';
|
||||||
|
export * from './label.model';
|
||||||
export * from './message.model';
|
export * from './message.model';
|
||||||
export * from './proxy.model';
|
export * from './proxy.model';
|
||||||
export * from './rabbitmq.model';
|
export * from './rabbitmq.model';
|
||||||
|
29
src/whatsapp/models/label.model.ts
Normal file
29
src/whatsapp/models/label.model.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Schema } from 'mongoose';
|
||||||
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
|
||||||
|
export class LabelRaw {
|
||||||
|
_id?: string;
|
||||||
|
id?: string;
|
||||||
|
owner: string;
|
||||||
|
name: string;
|
||||||
|
color: number;
|
||||||
|
predefinedId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type LabelRawBoolean<T> = {
|
||||||
|
[P in keyof T]?: 0 | 1;
|
||||||
|
};
|
||||||
|
export type LabelRawSelect = LabelRawBoolean<LabelRaw>;
|
||||||
|
|
||||||
|
const labelSchema = new Schema<LabelRaw>({
|
||||||
|
_id: { type: String, _id: true },
|
||||||
|
id: { type: String, required: true, minlength: 1 },
|
||||||
|
owner: { type: String, required: true, minlength: 1 },
|
||||||
|
name: { type: String, required: true, minlength: 1 },
|
||||||
|
color: { type: Number, required: true, min: 0, max: 19 },
|
||||||
|
predefinedId: { type: String },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const LabelModel = dbserver?.model(LabelRaw.name, labelSchema, 'labels');
|
||||||
|
export type ILabelModel = typeof LabelModel;
|
111
src/whatsapp/repository/label.repository.ts
Normal file
111
src/whatsapp/repository/label.repository.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { opendirSync, readFileSync, rmSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { ILabelModel, LabelRaw, LabelRawSelect } from '../models';
|
||||||
|
|
||||||
|
export class LabelQuery {
|
||||||
|
select?: LabelRawSelect;
|
||||||
|
where: Partial<LabelRaw>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LabelRepository extends Repository {
|
||||||
|
constructor(private readonly labelModel: ILabelModel, private readonly configService: ConfigService) {
|
||||||
|
super(configService);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly logger = new Logger('LabelRepository');
|
||||||
|
|
||||||
|
public async insert(data: LabelRaw, instanceName: string, saveDb = false): Promise<IInsert> {
|
||||||
|
this.logger.verbose('inserting labels');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.dbSettings.ENABLED && saveDb) {
|
||||||
|
this.logger.verbose('saving labels to db');
|
||||||
|
const insert = await this.labelModel.findOneAndUpdate({ id: data.id }, data, { upsert: true });
|
||||||
|
|
||||||
|
this.logger.verbose(`label ${data.name} saved to db`);
|
||||||
|
return { insertCount: Number(!!insert._id) };
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.verbose('saving label to store');
|
||||||
|
|
||||||
|
const store = this.configService.get<StoreConf>('STORE');
|
||||||
|
|
||||||
|
if (store.LABELS) {
|
||||||
|
this.logger.verbose('saving label to store');
|
||||||
|
this.writeStore<LabelRaw>({
|
||||||
|
path: join(this.storePath, 'labels', instanceName),
|
||||||
|
fileName: data.id,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
this.logger.verbose(
|
||||||
|
'labels saved to store in path: ' + join(this.storePath, 'labels', instanceName) + '/' + data.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.verbose(`label ${data.name} saved to store`);
|
||||||
|
return { insertCount: 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.verbose('labels not saved to store');
|
||||||
|
return { insertCount: 0 };
|
||||||
|
} catch (error) {
|
||||||
|
return error;
|
||||||
|
} finally {
|
||||||
|
data = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async find(query: LabelQuery): Promise<LabelRaw[]> {
|
||||||
|
try {
|
||||||
|
this.logger.verbose('finding labels');
|
||||||
|
if (this.dbSettings.ENABLED) {
|
||||||
|
this.logger.verbose('finding labels in db');
|
||||||
|
return await this.labelModel.find({ owner: query.where.owner }).select(query.select ?? {});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.verbose('finding labels in store');
|
||||||
|
|
||||||
|
const labels: LabelRaw[] = [];
|
||||||
|
const openDir = opendirSync(join(this.storePath, 'labels', query.where.owner));
|
||||||
|
for await (const dirent of openDir) {
|
||||||
|
if (dirent.isFile()) {
|
||||||
|
labels.push(
|
||||||
|
JSON.parse(
|
||||||
|
readFileSync(join(this.storePath, 'labels', query.where.owner, dirent.name), {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.verbose('labels found in store: ' + labels.length + ' labels');
|
||||||
|
return labels;
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async delete(query: LabelQuery) {
|
||||||
|
try {
|
||||||
|
this.logger.verbose('deleting labels');
|
||||||
|
if (this.dbSettings.ENABLED) {
|
||||||
|
this.logger.verbose('deleting labels in db');
|
||||||
|
return await this.labelModel.deleteOne({ ...query.where });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.verbose('deleting labels in store');
|
||||||
|
rmSync(join(this.storePath, 'labels', query.where.owner, query.where.id + '.josn'), {
|
||||||
|
force: true,
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { deleted: { labelId: query.where.id } };
|
||||||
|
} catch (error) {
|
||||||
|
return { error: error?.toString() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ import { ChamaaiRepository } from './chamaai.repository';
|
|||||||
import { ChatRepository } from './chat.repository';
|
import { ChatRepository } from './chat.repository';
|
||||||
import { ChatwootRepository } from './chatwoot.repository';
|
import { ChatwootRepository } from './chatwoot.repository';
|
||||||
import { ContactRepository } from './contact.repository';
|
import { ContactRepository } from './contact.repository';
|
||||||
|
import { LabelRepository } from './label.repository';
|
||||||
import { MessageRepository } from './message.repository';
|
import { MessageRepository } from './message.repository';
|
||||||
import { MessageUpRepository } from './messageUp.repository';
|
import { MessageUpRepository } from './messageUp.repository';
|
||||||
import { ProxyRepository } from './proxy.repository';
|
import { ProxyRepository } from './proxy.repository';
|
||||||
@ -34,6 +35,7 @@ export class RepositoryBroker {
|
|||||||
public readonly proxy: ProxyRepository,
|
public readonly proxy: ProxyRepository,
|
||||||
public readonly chamaai: ChamaaiRepository,
|
public readonly chamaai: ChamaaiRepository,
|
||||||
public readonly auth: AuthRepository,
|
public readonly auth: AuthRepository,
|
||||||
|
public readonly labels: LabelRepository,
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
dbServer?: MongoClient,
|
dbServer?: MongoClient,
|
||||||
) {
|
) {
|
||||||
|
@ -9,6 +9,7 @@ import { ChatRouter } from './chat.router';
|
|||||||
import { ChatwootRouter } from './chatwoot.router';
|
import { ChatwootRouter } from './chatwoot.router';
|
||||||
import { GroupRouter } from './group.router';
|
import { GroupRouter } from './group.router';
|
||||||
import { InstanceRouter } from './instance.router';
|
import { InstanceRouter } from './instance.router';
|
||||||
|
import { LabelRouter } from './label.router';
|
||||||
import { ProxyRouter } from './proxy.router';
|
import { ProxyRouter } from './proxy.router';
|
||||||
import { RabbitmqRouter } from './rabbitmq.router';
|
import { RabbitmqRouter } from './rabbitmq.router';
|
||||||
import { MessageRouter } from './sendMessage.router';
|
import { MessageRouter } from './sendMessage.router';
|
||||||
@ -61,6 +62,7 @@ router
|
|||||||
.use('/sqs', new SqsRouter(...guards).router)
|
.use('/sqs', new SqsRouter(...guards).router)
|
||||||
.use('/typebot', new TypebotRouter(...guards).router)
|
.use('/typebot', new TypebotRouter(...guards).router)
|
||||||
.use('/proxy', new ProxyRouter(...guards).router)
|
.use('/proxy', new ProxyRouter(...guards).router)
|
||||||
.use('/chamaai', new ChamaaiRouter(...guards).router);
|
.use('/chamaai', new ChamaaiRouter(...guards).router)
|
||||||
|
.use('/label', new LabelRouter(...guards).router);
|
||||||
|
|
||||||
export { HttpStatus, router };
|
export { HttpStatus, router };
|
||||||
|
53
src/whatsapp/routers/label.router.ts
Normal file
53
src/whatsapp/routers/label.router.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { handleLabelSchema } from '../../validate/validate.schema';
|
||||||
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
|
import { HandleLabelDto, LabelDto } from '../dto/label.dto';
|
||||||
|
import { labelController } from '../whatsapp.module';
|
||||||
|
import { HttpStatus } from './index.router';
|
||||||
|
|
||||||
|
const logger = new Logger('LabelRouter');
|
||||||
|
|
||||||
|
export class LabelRouter extends RouterBroker {
|
||||||
|
constructor(...guards: RequestHandler[]) {
|
||||||
|
super();
|
||||||
|
this.router
|
||||||
|
.get(this.routerPath('findLabels'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in findLabels');
|
||||||
|
logger.verbose('request body: ');
|
||||||
|
logger.verbose(req.body);
|
||||||
|
|
||||||
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
|
||||||
|
const response = await this.dataValidate<LabelDto>({
|
||||||
|
request: req,
|
||||||
|
schema: null,
|
||||||
|
ClassRef: LabelDto,
|
||||||
|
execute: (instance) => labelController.fetchLabels(instance),
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.put(this.routerPath('handleLabel'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in handleLabel');
|
||||||
|
logger.verbose('request body: ');
|
||||||
|
logger.verbose(req.body);
|
||||||
|
|
||||||
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
|
||||||
|
const response = await this.dataValidate<HandleLabelDto>({
|
||||||
|
request: req,
|
||||||
|
schema: handleLabelSchema,
|
||||||
|
ClassRef: HandleLabelDto,
|
||||||
|
execute: (instance, data) => labelController.handleLabel(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(HttpStatus.OK).json(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly router = Router();
|
||||||
|
}
|
@ -15,6 +15,7 @@ import {
|
|||||||
ChamaaiModel,
|
ChamaaiModel,
|
||||||
// ChatModel,
|
// ChatModel,
|
||||||
ChatwootModel,
|
ChatwootModel,
|
||||||
|
LabelModel,
|
||||||
// ContactModel,
|
// ContactModel,
|
||||||
// MessageModel,
|
// MessageModel,
|
||||||
// MessageUpModel,
|
// MessageUpModel,
|
||||||
@ -320,6 +321,7 @@ export class WAMonitoringService {
|
|||||||
execSync(`rm -rf ${join(STORE_DIR, 'typebot', instanceName + '*')}`);
|
execSync(`rm -rf ${join(STORE_DIR, 'typebot', instanceName + '*')}`);
|
||||||
execSync(`rm -rf ${join(STORE_DIR, 'websocket', instanceName + '*')}`);
|
execSync(`rm -rf ${join(STORE_DIR, 'websocket', instanceName + '*')}`);
|
||||||
execSync(`rm -rf ${join(STORE_DIR, 'settings', instanceName + '*')}`);
|
execSync(`rm -rf ${join(STORE_DIR, 'settings', instanceName + '*')}`);
|
||||||
|
execSync(`rm -rf ${join(STORE_DIR, 'labels', instanceName + '*')}`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -340,6 +342,7 @@ export class WAMonitoringService {
|
|||||||
await TypebotModel.deleteMany({ _id: instanceName });
|
await TypebotModel.deleteMany({ _id: instanceName });
|
||||||
await WebsocketModel.deleteMany({ _id: instanceName });
|
await WebsocketModel.deleteMany({ _id: instanceName });
|
||||||
await SettingsModel.deleteMany({ _id: instanceName });
|
await SettingsModel.deleteMany({ _id: instanceName });
|
||||||
|
await LabelModel.deleteMany({ owner: instanceName });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@ import makeWASocket, {
|
|||||||
WAMessageUpdate,
|
WAMessageUpdate,
|
||||||
WASocket,
|
WASocket,
|
||||||
} from '@whiskeysockets/baileys';
|
} from '@whiskeysockets/baileys';
|
||||||
|
import { Label } from '@whiskeysockets/baileys/lib/Types/Label';
|
||||||
|
import { LabelAssociation } from '@whiskeysockets/baileys/lib/Types/LabelAssociation';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { exec, execSync } from 'child_process';
|
import { exec, execSync } from 'child_process';
|
||||||
import { arrayUnique, isBase64, isURL } from 'class-validator';
|
import { arrayUnique, isBase64, isURL } from 'class-validator';
|
||||||
@ -105,6 +107,7 @@ import {
|
|||||||
GroupUpdateSettingDto,
|
GroupUpdateSettingDto,
|
||||||
} from '../dto/group.dto';
|
} from '../dto/group.dto';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { HandleLabelDto, LabelDto } from '../dto/label.dto';
|
||||||
import {
|
import {
|
||||||
ContactMessage,
|
ContactMessage,
|
||||||
MediaMessage,
|
MediaMessage,
|
||||||
@ -2147,6 +2150,53 @@ export class WAStartupService {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private readonly labelHandle = {
|
||||||
|
[Events.LABELS_EDIT]: async (label: Label, database: Database) => {
|
||||||
|
this.logger.verbose('Event received: labels.edit');
|
||||||
|
this.logger.verbose('Finding labels in database');
|
||||||
|
const labelsRepository = await this.repository.labels.find({
|
||||||
|
where: { owner: this.instance.name },
|
||||||
|
});
|
||||||
|
|
||||||
|
const savedLabel = labelsRepository.find((l) => l.id === label.id);
|
||||||
|
if (label.deleted && savedLabel) {
|
||||||
|
this.logger.verbose('Sending data to webhook in event LABELS_EDIT');
|
||||||
|
await this.repository.labels.delete({
|
||||||
|
where: { owner: this.instance.name, id: label.id },
|
||||||
|
});
|
||||||
|
this.sendDataWebhook(Events.LABELS_EDIT, { ...label, instance: this.instance.name });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const labelName = label.name.replace(/[^\x20-\x7E]/g, '');
|
||||||
|
if (!savedLabel || savedLabel.color !== label.color || savedLabel.name !== labelName) {
|
||||||
|
this.logger.verbose('Sending data to webhook in event LABELS_EDIT');
|
||||||
|
await this.repository.labels.insert(
|
||||||
|
{
|
||||||
|
color: label.color,
|
||||||
|
name: labelName,
|
||||||
|
owner: this.instance.name,
|
||||||
|
id: label.id,
|
||||||
|
predefinedId: label.predefinedId,
|
||||||
|
},
|
||||||
|
this.instance.name,
|
||||||
|
database.SAVE_DATA.LABELS,
|
||||||
|
);
|
||||||
|
this.sendDataWebhook(Events.LABELS_EDIT, { ...label, instance: this.instance.name });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
[Events.LABELS_ASSOCIATION]: async (data: { association: LabelAssociation; type: 'remove' | 'add' }) => {
|
||||||
|
this.logger.verbose('Sending data to webhook in event LABELS_ASSOCIATION');
|
||||||
|
this.sendDataWebhook(Events.LABELS_ASSOCIATION, {
|
||||||
|
instance: this.instance.name,
|
||||||
|
type: data.type,
|
||||||
|
jid: data.association.chatId,
|
||||||
|
labelId: data.association.labelId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
private eventHandler() {
|
private eventHandler() {
|
||||||
this.logger.verbose('Initializing event handler');
|
this.logger.verbose('Initializing event handler');
|
||||||
this.client.ev.process(async (events) => {
|
this.client.ev.process(async (events) => {
|
||||||
@ -2282,6 +2332,19 @@ export class WAStartupService {
|
|||||||
this.logger.verbose('Listening event: contacts.update');
|
this.logger.verbose('Listening event: contacts.update');
|
||||||
const payload = events['contacts.update'];
|
const payload = events['contacts.update'];
|
||||||
this.contactHandle['contacts.update'](payload, database);
|
this.contactHandle['contacts.update'](payload, database);
|
||||||
|
|
||||||
|
if (events[Events.LABELS_ASSOCIATION]) {
|
||||||
|
this.logger.verbose('Listening event: labels.association');
|
||||||
|
const payload = events[Events.LABELS_ASSOCIATION];
|
||||||
|
this.labelHandle[Events.LABELS_ASSOCIATION](payload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events[Events.LABELS_EDIT]) {
|
||||||
|
this.logger.verbose('Listening event: labels.edit');
|
||||||
|
const payload = events[Events.LABELS_EDIT];
|
||||||
|
this.labelHandle[Events.LABELS_EDIT](payload, database);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -4005,4 +4068,47 @@ export class WAStartupService {
|
|||||||
throw new BadRequestException('Unable to leave the group', error.toString());
|
throw new BadRequestException('Unable to leave the group', error.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async fetchLabels(): Promise<LabelDto[]> {
|
||||||
|
this.logger.verbose('Fetching labels');
|
||||||
|
const labels = await this.repository.labels.find({
|
||||||
|
where: {
|
||||||
|
owner: this.instance.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return labels.map((label) => ({
|
||||||
|
color: label.color,
|
||||||
|
name: label.name,
|
||||||
|
id: label.id,
|
||||||
|
predefinedId: label.predefinedId,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleLabel(data: HandleLabelDto) {
|
||||||
|
this.logger.verbose('Adding label');
|
||||||
|
const whatsappContact = await this.whatsappNumber({ numbers: [data.number] });
|
||||||
|
if (whatsappContact.length === 0) {
|
||||||
|
throw new NotFoundException('Number not found');
|
||||||
|
}
|
||||||
|
const contact = whatsappContact[0];
|
||||||
|
if (!contact.exists) {
|
||||||
|
throw new NotFoundException('Number is not on WhatsApp');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (data.action === 'add') {
|
||||||
|
await this.client.addChatLabel(contact.jid, data.labelId);
|
||||||
|
|
||||||
|
return { numberJid: contact.jid, labelId: data.labelId, add: true };
|
||||||
|
}
|
||||||
|
if (data.action === 'remove') {
|
||||||
|
await this.client.removeChatLabel(contact.jid, data.labelId);
|
||||||
|
|
||||||
|
return { numberJid: contact.jid, labelId: data.labelId, remove: true };
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new BadRequestException(`Unable to ${data.action} label to chat`, error.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,10 @@ export enum Events {
|
|||||||
TYPEBOT_START = 'typebot.start',
|
TYPEBOT_START = 'typebot.start',
|
||||||
TYPEBOT_CHANGE_STATUS = 'typebot.change-status',
|
TYPEBOT_CHANGE_STATUS = 'typebot.change-status',
|
||||||
CHAMA_AI_ACTION = 'chama-ai.action',
|
CHAMA_AI_ACTION = 'chama-ai.action',
|
||||||
|
LABELS_EDIT = 'labels.edit',
|
||||||
|
LABELS_ASSOCIATION = 'labels.association',
|
||||||
|
CREDS_UPDATE = 'creds.update',
|
||||||
|
MESSAGING_HISTORY_SET = 'messaging-history.set',
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare namespace wa {
|
export declare namespace wa {
|
||||||
|
@ -9,6 +9,7 @@ import { ChatController } from './controllers/chat.controller';
|
|||||||
import { ChatwootController } from './controllers/chatwoot.controller';
|
import { ChatwootController } from './controllers/chatwoot.controller';
|
||||||
import { GroupController } from './controllers/group.controller';
|
import { GroupController } from './controllers/group.controller';
|
||||||
import { InstanceController } from './controllers/instance.controller';
|
import { InstanceController } from './controllers/instance.controller';
|
||||||
|
import { LabelController } from './controllers/label.controller';
|
||||||
import { ProxyController } from './controllers/proxy.controller';
|
import { ProxyController } from './controllers/proxy.controller';
|
||||||
import { RabbitmqController } from './controllers/rabbitmq.controller';
|
import { RabbitmqController } from './controllers/rabbitmq.controller';
|
||||||
import { SendMessageController } from './controllers/sendMessage.controller';
|
import { SendMessageController } from './controllers/sendMessage.controller';
|
||||||
@ -33,11 +34,13 @@ import {
|
|||||||
WebhookModel,
|
WebhookModel,
|
||||||
WebsocketModel,
|
WebsocketModel,
|
||||||
} from './models';
|
} from './models';
|
||||||
|
import { LabelModel } from './models/label.model';
|
||||||
import { AuthRepository } from './repository/auth.repository';
|
import { AuthRepository } from './repository/auth.repository';
|
||||||
import { ChamaaiRepository } from './repository/chamaai.repository';
|
import { ChamaaiRepository } from './repository/chamaai.repository';
|
||||||
import { ChatRepository } from './repository/chat.repository';
|
import { ChatRepository } from './repository/chat.repository';
|
||||||
import { ChatwootRepository } from './repository/chatwoot.repository';
|
import { ChatwootRepository } from './repository/chatwoot.repository';
|
||||||
import { ContactRepository } from './repository/contact.repository';
|
import { ContactRepository } from './repository/contact.repository';
|
||||||
|
import { LabelRepository } from './repository/label.repository';
|
||||||
import { MessageRepository } from './repository/message.repository';
|
import { MessageRepository } from './repository/message.repository';
|
||||||
import { MessageUpRepository } from './repository/messageUp.repository';
|
import { MessageUpRepository } from './repository/messageUp.repository';
|
||||||
import { ProxyRepository } from './repository/proxy.repository';
|
import { ProxyRepository } from './repository/proxy.repository';
|
||||||
@ -77,6 +80,7 @@ const sqsRepository = new SqsRepository(SqsModel, configService);
|
|||||||
const chatwootRepository = new ChatwootRepository(ChatwootModel, configService);
|
const chatwootRepository = new ChatwootRepository(ChatwootModel, configService);
|
||||||
const settingsRepository = new SettingsRepository(SettingsModel, configService);
|
const settingsRepository = new SettingsRepository(SettingsModel, configService);
|
||||||
const authRepository = new AuthRepository(AuthModel, configService);
|
const authRepository = new AuthRepository(AuthModel, configService);
|
||||||
|
const labelRepository = new LabelRepository(LabelModel, configService);
|
||||||
|
|
||||||
export const repository = new RepositoryBroker(
|
export const repository = new RepositoryBroker(
|
||||||
messageRepository,
|
messageRepository,
|
||||||
@ -93,6 +97,7 @@ export const repository = new RepositoryBroker(
|
|||||||
proxyRepository,
|
proxyRepository,
|
||||||
chamaaiRepository,
|
chamaaiRepository,
|
||||||
authRepository,
|
authRepository,
|
||||||
|
labelRepository,
|
||||||
configService,
|
configService,
|
||||||
dbserver?.getClient(),
|
dbserver?.getClient(),
|
||||||
);
|
);
|
||||||
@ -160,5 +165,6 @@ export const instanceController = new InstanceController(
|
|||||||
export const sendMessageController = new SendMessageController(waMonitor);
|
export const sendMessageController = new SendMessageController(waMonitor);
|
||||||
export const chatController = new ChatController(waMonitor);
|
export const chatController = new ChatController(waMonitor);
|
||||||
export const groupController = new GroupController(waMonitor);
|
export const groupController = new GroupController(waMonitor);
|
||||||
|
export const labelController = new LabelController(waMonitor);
|
||||||
|
|
||||||
logger.info('Module - ON');
|
logger.info('Module - ON');
|
||||||
|
Loading…
Reference in New Issue
Block a user