mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-12-25 22:57:44 -06:00
init project evolution api
This commit is contained in:
101
src/whatsapp/controllers/chat.controller.ts
Normal file
101
src/whatsapp/controllers/chat.controller.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { proto } from '@evolution/base';
|
||||
import {
|
||||
ArchiveChatDto,
|
||||
DeleteMessage,
|
||||
NumberDto,
|
||||
ProfileNameDto,
|
||||
ProfilePictureDto,
|
||||
ProfileStatusDto,
|
||||
ReadMessageDto,
|
||||
WhatsAppNumberDto,
|
||||
} from '../dto/chat.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ContactQuery } from '../repository/contact.repository';
|
||||
import { MessageQuery } from '../repository/message.repository';
|
||||
import { MessageUpQuery } from '../repository/messageUp.repository';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
|
||||
export class ChatController {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
public async whatsappNumber({ instanceName }: InstanceDto, data: WhatsAppNumberDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].whatsappNumber(data);
|
||||
}
|
||||
|
||||
public async readMessage({ instanceName }: InstanceDto, data: ReadMessageDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].markMessageAsRead(data);
|
||||
}
|
||||
|
||||
public async archiveChat({ instanceName }: InstanceDto, data: ArchiveChatDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].archiveChat(data);
|
||||
}
|
||||
|
||||
public async deleteMessage({ instanceName }: InstanceDto, data: DeleteMessage) {
|
||||
return await this.waMonitor.waInstances[instanceName].deleteMessage(data);
|
||||
}
|
||||
|
||||
public async fetchProfilePicture({ instanceName }: InstanceDto, data: NumberDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].profilePicture(data.number);
|
||||
}
|
||||
|
||||
public async fetchContacts({ instanceName }: InstanceDto, query: ContactQuery) {
|
||||
return await this.waMonitor.waInstances[instanceName].fetchContacts(query);
|
||||
}
|
||||
|
||||
public async getBase64FromMediaMessage(
|
||||
{ instanceName }: InstanceDto,
|
||||
message: proto.IWebMessageInfo,
|
||||
) {
|
||||
return await this.waMonitor.waInstances[instanceName].getBase64FromMediaMessage(
|
||||
message,
|
||||
);
|
||||
}
|
||||
|
||||
public async fetchMessages({ instanceName }: InstanceDto, query: MessageQuery) {
|
||||
return await this.waMonitor.waInstances[instanceName].fetchMessages(query);
|
||||
}
|
||||
|
||||
public async fetchStatusMessage({ instanceName }: InstanceDto, query: MessageUpQuery) {
|
||||
return await this.waMonitor.waInstances[instanceName].fetchStatusMessage(query);
|
||||
}
|
||||
|
||||
public async fetchChats({ instanceName }: InstanceDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].fetchChats();
|
||||
}
|
||||
|
||||
public async getBusinessProfile(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: ProfilePictureDto,
|
||||
) {
|
||||
return await this.waMonitor.waInstances[instanceName].getBusinessProfile(data.number);
|
||||
}
|
||||
|
||||
public async updateProfileName({ instanceName }: InstanceDto, data: ProfileNameDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].updateProfileName(data.name);
|
||||
}
|
||||
|
||||
public async updateProfileStatus(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: ProfileStatusDto,
|
||||
) {
|
||||
return await this.waMonitor.waInstances[instanceName].updateProfileStatus(
|
||||
data.status,
|
||||
);
|
||||
}
|
||||
|
||||
public async updateProfilePicture(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: ProfilePictureDto,
|
||||
) {
|
||||
return await this.waMonitor.waInstances[instanceName].updateProfilePicture(
|
||||
data.picture,
|
||||
);
|
||||
}
|
||||
|
||||
public async removeProfilePicture(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: ProfilePictureDto,
|
||||
) {
|
||||
return await this.waMonitor.waInstances[instanceName].removeProfilePicture();
|
||||
}
|
||||
}
|
||||
72
src/whatsapp/controllers/group.controller.ts
Normal file
72
src/whatsapp/controllers/group.controller.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
CreateGroupDto,
|
||||
GroupInvite,
|
||||
GroupJid,
|
||||
GroupPictureDto,
|
||||
GroupToggleEphemeralDto,
|
||||
GroupUpdateParticipantDto,
|
||||
GroupUpdateSettingDto,
|
||||
} from '../dto/group.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
|
||||
export class GroupController {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
public async createGroup(instance: InstanceDto, create: CreateGroupDto) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].createGroup(create);
|
||||
}
|
||||
|
||||
public async updateGroupPicture(instance: InstanceDto, update: GroupPictureDto) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupPicture(
|
||||
update,
|
||||
);
|
||||
}
|
||||
|
||||
public async findGroupInfo(instance: InstanceDto, groupJid: GroupJid) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].findGroup(groupJid);
|
||||
}
|
||||
|
||||
public async inviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].inviteCode(groupJid);
|
||||
}
|
||||
|
||||
public async inviteInfo(instance: InstanceDto, inviteCode: GroupInvite) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].inviteInfo(inviteCode);
|
||||
}
|
||||
|
||||
public async revokeInviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].revokeInviteCode(
|
||||
groupJid,
|
||||
);
|
||||
}
|
||||
|
||||
public async findParticipants(instance: InstanceDto, groupJid: GroupJid) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].findParticipants(
|
||||
groupJid,
|
||||
);
|
||||
}
|
||||
|
||||
public async updateGParticipate(
|
||||
instance: InstanceDto,
|
||||
update: GroupUpdateParticipantDto,
|
||||
) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGParticipant(
|
||||
update,
|
||||
);
|
||||
}
|
||||
|
||||
public async updateGSetting(instance: InstanceDto, update: GroupUpdateSettingDto) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGSetting(update);
|
||||
}
|
||||
|
||||
public async toggleEphemeral(instance: InstanceDto, update: GroupToggleEphemeralDto) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].toggleEphemeral(
|
||||
update,
|
||||
);
|
||||
}
|
||||
|
||||
public async leaveGroup(instance: InstanceDto, groupJid: GroupJid) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].leaveGroup(groupJid);
|
||||
}
|
||||
}
|
||||
166
src/whatsapp/controllers/instance.controller.ts
Normal file
166
src/whatsapp/controllers/instance.controller.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { delay } from '@evolution/base';
|
||||
import EventEmitter2 from 'eventemitter2';
|
||||
import { Auth, ConfigService } from '../../config/env.config';
|
||||
import { BadRequestException, InternalServerErrorException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { RepositoryBroker } from '../repository/repository.manager';
|
||||
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 { Logger } from '../../config/logger.config';
|
||||
|
||||
export class InstanceController {
|
||||
constructor(
|
||||
private readonly waMonitor: WAMonitoringService,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly repository: RepositoryBroker,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly authService: AuthService,
|
||||
private readonly webhookService: WebhookService,
|
||||
) {}
|
||||
|
||||
private readonly logger = new Logger(InstanceController.name);
|
||||
|
||||
public async createInstance({ instanceName, webhook }: InstanceDto) {
|
||||
//verifica se modo da instancia é container
|
||||
const mode = this.configService.get<Auth>('AUTHENTICATION').INSTANCE.MODE;
|
||||
|
||||
if (mode === 'container') {
|
||||
//verifica se ja existe uma instancia criada com qualquer nome
|
||||
if (Object.keys(this.waMonitor.waInstances).length > 0) {
|
||||
throw new BadRequestException([
|
||||
'Instance already created',
|
||||
'Only one instance can be created',
|
||||
]);
|
||||
}
|
||||
|
||||
const instance = new WAStartupService(
|
||||
this.configService,
|
||||
this.eventEmitter,
|
||||
this.repository,
|
||||
);
|
||||
instance.instanceName = instanceName;
|
||||
this.waMonitor.waInstances[instance.instanceName] = instance;
|
||||
this.waMonitor.delInstanceTime(instance.instanceName);
|
||||
|
||||
const hash = await this.authService.generateHash({
|
||||
instanceName: instance.instanceName,
|
||||
});
|
||||
|
||||
if (webhook) {
|
||||
try {
|
||||
this.webhookService.create(instance, { enabled: true, url: webhook });
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
instance: {
|
||||
instanceName: instance.instanceName,
|
||||
status: 'created',
|
||||
},
|
||||
hash,
|
||||
webhook,
|
||||
};
|
||||
} else {
|
||||
const instance = new WAStartupService(
|
||||
this.configService,
|
||||
this.eventEmitter,
|
||||
this.repository,
|
||||
);
|
||||
instance.instanceName = instanceName;
|
||||
this.waMonitor.waInstances[instance.instanceName] = instance;
|
||||
this.waMonitor.delInstanceTime(instance.instanceName);
|
||||
|
||||
const hash = await this.authService.generateHash({
|
||||
instanceName: instance.instanceName,
|
||||
});
|
||||
|
||||
if (webhook) {
|
||||
try {
|
||||
this.webhookService.create(instance, { enabled: true, url: webhook });
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
instance: {
|
||||
instanceName: instance.instanceName,
|
||||
status: 'created',
|
||||
},
|
||||
hash,
|
||||
webhook,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public async connectToWhatsapp({ instanceName }: InstanceDto) {
|
||||
try {
|
||||
const instance = this.waMonitor.waInstances[instanceName];
|
||||
const state = instance.connectionStatus?.state;
|
||||
|
||||
switch (state) {
|
||||
case 'close':
|
||||
await instance.connectToWhatsapp();
|
||||
await delay(2000);
|
||||
return instance.qrCode;
|
||||
case 'connecting':
|
||||
return instance.qrCode;
|
||||
default:
|
||||
return await this.connectionState({ instanceName });
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
public async connectionState({ instanceName }: InstanceDto) {
|
||||
return this.waMonitor.waInstances[instanceName].connectionStatus;
|
||||
}
|
||||
|
||||
public async fetchInstances({ instanceName }: InstanceDto) {
|
||||
if (instanceName) {
|
||||
return this.waMonitor.instanceInfo(instanceName);
|
||||
}
|
||||
|
||||
return this.waMonitor.instanceInfo();
|
||||
}
|
||||
|
||||
public async logout({ instanceName }: InstanceDto) {
|
||||
try {
|
||||
await this.waMonitor.waInstances[instanceName]?.client?.logout(
|
||||
'Log out instance: ' + instanceName,
|
||||
);
|
||||
|
||||
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
||||
this.waMonitor.waInstances[instanceName]?.client?.end(undefined);
|
||||
|
||||
return { error: false, message: 'Instance logged out' };
|
||||
} catch (error) {
|
||||
throw new InternalServerErrorException(error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public async deleteInstance({ instanceName }: InstanceDto) {
|
||||
const stateConn = await this.connectionState({ instanceName });
|
||||
if (stateConn.state === 'open') {
|
||||
throw new BadRequestException([
|
||||
'Deletion failed',
|
||||
'The instance needs to be disconnected',
|
||||
]);
|
||||
}
|
||||
try {
|
||||
delete this.waMonitor.waInstances[instanceName];
|
||||
return { error: false, message: 'Instance deleted' };
|
||||
} catch (error) {
|
||||
throw new BadRequestException(error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public async refreshToken(_: InstanceDto, oldToken: OldToken) {
|
||||
return await this.authService.refreshToken(oldToken);
|
||||
}
|
||||
}
|
||||
78
src/whatsapp/controllers/sendMessage.controller.ts
Normal file
78
src/whatsapp/controllers/sendMessage.controller.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { isBase64, isURL } from 'class-validator';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import {
|
||||
SendAudioDto,
|
||||
SendButtonDto,
|
||||
SendContactDto,
|
||||
SendLinkPreviewDto,
|
||||
SendListDto,
|
||||
SendLocationDto,
|
||||
SendMediaDto,
|
||||
SendPollDto,
|
||||
SendReactionDto,
|
||||
SendTextDto,
|
||||
} from '../dto/sendMessage.dto';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
|
||||
export class SendMessageController {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
public async sendText({ instanceName }: InstanceDto, data: SendTextDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].textMessage(data);
|
||||
}
|
||||
|
||||
public async sendMedia({ instanceName }: InstanceDto, data: SendMediaDto) {
|
||||
if (isBase64(data?.mediaMessage?.media) && !data?.mediaMessage?.fileName) {
|
||||
throw new BadRequestException('For bse64 the file name must be informed.');
|
||||
}
|
||||
if (isURL(data?.mediaMessage?.media) || isBase64(data?.mediaMessage?.media)) {
|
||||
return await this.waMonitor.waInstances[instanceName].mediaMessage(data);
|
||||
}
|
||||
throw new BadRequestException('Owned media must be a url or base64');
|
||||
}
|
||||
|
||||
public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) {
|
||||
if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) {
|
||||
return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data);
|
||||
}
|
||||
throw new BadRequestException('Owned media must be a url or base64');
|
||||
}
|
||||
|
||||
public async sendButtons({ instanceName }: InstanceDto, data: SendButtonDto) {
|
||||
if (
|
||||
isBase64(data.buttonMessage.mediaMessage?.media) &&
|
||||
!data.buttonMessage.mediaMessage?.fileName
|
||||
) {
|
||||
throw new BadRequestException('For bse64 the file name must be informed.');
|
||||
}
|
||||
return await this.waMonitor.waInstances[instanceName].buttonMessage(data);
|
||||
}
|
||||
|
||||
public async sendLocation({ instanceName }: InstanceDto, data: SendLocationDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].locationMessage(data);
|
||||
}
|
||||
|
||||
public async sendList({ instanceName }: InstanceDto, data: SendListDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].listMessage(data);
|
||||
}
|
||||
|
||||
public async sendContact({ instanceName }: InstanceDto, data: SendContactDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].contactMessage(data);
|
||||
}
|
||||
|
||||
public async sendReaction({ instanceName }: InstanceDto, data: SendReactionDto) {
|
||||
if (!data.reactionMessage.reaction.match(/[^\(\)\w\sà-ú"-\+]+/)) {
|
||||
throw new BadRequestException('"reaction" must be an emoji');
|
||||
}
|
||||
return await this.waMonitor.waInstances[instanceName].reactionMessage(data);
|
||||
}
|
||||
|
||||
public async sendPoll({ instanceName }: InstanceDto, data: SendPollDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].pollMessage(data);
|
||||
}
|
||||
|
||||
public async sendLinkPreview({ instanceName }: InstanceDto, data: SendLinkPreviewDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].linkPreview(data);
|
||||
}
|
||||
}
|
||||
28
src/whatsapp/controllers/views.controller.ts
Normal file
28
src/whatsapp/controllers/views.controller.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { Auth, ConfigService } from '../../config/env.config';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { HttpStatus } from '../routers/index.router';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
|
||||
export class ViewsController {
|
||||
constructor(
|
||||
private readonly waMonit: WAMonitoringService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
|
||||
public async qrcode(request: Request, response: Response) {
|
||||
try {
|
||||
const param = request.params as unknown as InstanceDto;
|
||||
const instance = this.waMonit.waInstances[param.instanceName];
|
||||
if (instance.connectionStatus.state === 'open') {
|
||||
throw new BadRequestException('The instance is already connected');
|
||||
}
|
||||
const type = this.configService.get<Auth>('AUTHENTICATION').TYPE;
|
||||
|
||||
return response.status(HttpStatus.OK).render('qrcode', { type, ...param });
|
||||
} catch (error) {
|
||||
console.log('ERROR: ', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/whatsapp/controllers/webhook.controller.ts
Normal file
20
src/whatsapp/controllers/webhook.controller.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { isURL } from 'class-validator';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WebhookDto } from '../dto/webhook.dto';
|
||||
import { WebhookService } from '../services/webhook.service';
|
||||
|
||||
export class WebhookController {
|
||||
constructor(private readonly webhookService: WebhookService) {}
|
||||
|
||||
public async createWebhook(instance: InstanceDto, data: WebhookDto) {
|
||||
if (!isURL(data.url, { require_tld: false })) {
|
||||
throw new BadRequestException('Invalid "url" property');
|
||||
}
|
||||
return this.webhookService.create(instance, data);
|
||||
}
|
||||
|
||||
public async findWebhook(instance: InstanceDto) {
|
||||
return this.webhookService.find(instance);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user