mirror of
https://github.com/cheveguerra/api-whatsapp-ts.git
synced 2026-04-18 03:39:19 +00:00
first
This commit is contained in:
11
src/app.ts
Normal file
11
src/app.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import "dotenv/config"
|
||||
import express from "express"
|
||||
import cors from "cors"
|
||||
import routes from "./infrastructure/router"
|
||||
const port = process.env.PORT || 3001
|
||||
const app = express()
|
||||
app.use(cors())
|
||||
app.use(express.json())
|
||||
app.use(`/`,routes)
|
||||
|
||||
app.listen(port, () => console.log(`Ready...${port}`))
|
||||
24
src/application/lead.create.ts
Normal file
24
src/application/lead.create.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import LeadExternal from "../domain/lead.external";
|
||||
import LeadRepository from "../domain/lead.repository";
|
||||
|
||||
export class LeadCreate {
|
||||
private leadRepository: LeadRepository;
|
||||
private leadExternal: LeadExternal;
|
||||
constructor(respositories: [LeadRepository, LeadExternal]) {
|
||||
const [leadRepository, leadExternal] = respositories;
|
||||
this.leadRepository = leadRepository;
|
||||
this.leadExternal = leadExternal;
|
||||
}
|
||||
|
||||
public async sendMessageAndSave({
|
||||
message,
|
||||
phone,
|
||||
}: {
|
||||
message: string;
|
||||
phone: string;
|
||||
}) {
|
||||
const responseDbSave = await this.leadRepository.save({ message, phone });//TODO DB
|
||||
const responseExSave = await this.leadExternal.sendMsg({ message, phone });//TODO enviar a ws
|
||||
return {responseDbSave, responseExSave};
|
||||
}
|
||||
}
|
||||
3
src/domain/lead.external.ts
Normal file
3
src/domain/lead.external.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default interface LeadExternal {
|
||||
sendMsg({message, phone}:{message:string, phone:string}):Promise<any>
|
||||
}
|
||||
12
src/domain/lead.repository.ts
Normal file
12
src/domain/lead.repository.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Lead } from "./lead";
|
||||
|
||||
export default interface LeadRepository {
|
||||
save({
|
||||
message,
|
||||
phone,
|
||||
}: {
|
||||
message: string;
|
||||
phone: string;
|
||||
}): Promise<Lead | undefined | null>;
|
||||
getDetail(id:string):Promise<Lead | null | undefined>
|
||||
}
|
||||
13
src/domain/lead.ts
Normal file
13
src/domain/lead.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
export class Lead {
|
||||
readonly uuid: string;
|
||||
readonly message: string;
|
||||
readonly phone: string;
|
||||
|
||||
constructor({ message, phone }: { message: string; phone: string }) {
|
||||
this.uuid = uuid();
|
||||
this.message = message;
|
||||
this.phone = phone;
|
||||
}
|
||||
}
|
||||
14
src/infrastructure/controller/lead.ctrl.ts
Normal file
14
src/infrastructure/controller/lead.ctrl.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Request, Response } from "express";
|
||||
import { LeadCreate } from "../../application/lead.create";
|
||||
|
||||
class LeadCtrl {
|
||||
constructor(private readonly leadCreator: LeadCreate) {}
|
||||
|
||||
public sendCtrl = async ({ body }: Request, res: Response) => {
|
||||
const { message, phone } = body;
|
||||
const response = await this.leadCreator.sendMessageAndSave({ message, phone })
|
||||
res.send(response);
|
||||
};
|
||||
}
|
||||
|
||||
export default LeadCtrl;
|
||||
26
src/infrastructure/ioc.ts
Normal file
26
src/infrastructure/ioc.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { ContainerBuilder } from "node-dependency-injection";
|
||||
import { LeadCreate } from "../application/lead.create";
|
||||
import LeadCtrl from "./controller/lead.ctrl";
|
||||
import MockRepository from "./repositories/mock.repository";
|
||||
import WsTransporter from "./repositories/ws.external";
|
||||
|
||||
const container = new ContainerBuilder();
|
||||
|
||||
/**
|
||||
* Inicamos servicio de WS / Bot / Twilio
|
||||
*/
|
||||
container.register("ws.transporter", WsTransporter);
|
||||
const wsTransporter = container.get("ws.transporter");
|
||||
|
||||
container.register("db.repository", MockRepository);
|
||||
const dbRepository = container.get("db.repository");
|
||||
|
||||
container
|
||||
.register("lead.creator", LeadCreate)
|
||||
.addArgument([dbRepository, wsTransporter]);
|
||||
|
||||
const leadCreator = container.get("lead.creator");
|
||||
|
||||
container.register("lead.ctrl", LeadCtrl).addArgument(leadCreator);
|
||||
|
||||
export default container;
|
||||
18
src/infrastructure/repositories/mock.repository.ts
Normal file
18
src/infrastructure/repositories/mock.repository.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Lead } from "../../domain/lead";
|
||||
import LeadRepository from "../../domain/lead.repository";
|
||||
|
||||
class MockRepository implements LeadRepository {
|
||||
getDetail(id: string): Promise<Lead | null | undefined> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
save(): Promise<Lead> {
|
||||
const MOCK_LEAD: Lead = {
|
||||
uuid: "00---000",
|
||||
message: "test",
|
||||
phone: "00000",
|
||||
};
|
||||
return Promise.resolve(MOCK_LEAD);
|
||||
}
|
||||
}
|
||||
|
||||
export default MockRepository
|
||||
8
src/infrastructure/repositories/twilio.repository.ts
Normal file
8
src/infrastructure/repositories/twilio.repository.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import LeadExternal from "../../domain/lead.external";
|
||||
|
||||
export class TwilioService implements LeadExternal {
|
||||
sendMsg({ message, phone }: { message: string; phone: string; }): Promise<any> {
|
||||
return Promise.resolve('SE_ENVIO_CORRECTAMENTE')
|
||||
}
|
||||
|
||||
}
|
||||
63
src/infrastructure/repositories/ws.external.ts
Normal file
63
src/infrastructure/repositories/ws.external.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Client, LocalAuth } from "whatsapp-web.js";
|
||||
import { image as imageQr } from "qr-image";
|
||||
import LeadExternal from "../../domain/lead.external";
|
||||
|
||||
/**
|
||||
* Extendemos los super poderes de whatsapp-web
|
||||
*/
|
||||
class WsTransporter extends Client implements LeadExternal {
|
||||
private status = false;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
authStrategy: new LocalAuth(),
|
||||
puppeteer: { headless: true },
|
||||
});
|
||||
|
||||
console.log("Iniciando....");
|
||||
|
||||
this.initialize();
|
||||
|
||||
this.on("ready", () => {
|
||||
this.status = true;
|
||||
console.log("LOGIN_SUCCESS");
|
||||
});
|
||||
|
||||
this.on("auth_failure", () => {
|
||||
this.status = false;
|
||||
console.log("LOGIN_FAIL");
|
||||
});
|
||||
|
||||
this.on("qr", (qr) => this.generateImage(qr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enviar mensaje de WS
|
||||
* @param lead
|
||||
* @returns
|
||||
*/
|
||||
async sendMsg(lead: { message: string; phone: string }): Promise<any> {
|
||||
try {
|
||||
if (!this.status) return Promise.resolve({ error: "WAIT_LOGIN" });
|
||||
const { message, phone } = lead;
|
||||
const response = await this.sendMessage(`${phone}@c.us`, message);
|
||||
return { id: response.id.id };
|
||||
} catch (e: any) {
|
||||
return Promise.resolve({ error: e.message });
|
||||
}
|
||||
}
|
||||
|
||||
getStatus(): boolean {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
private generateImage = (base64: string) => {
|
||||
const path = `${process.cwd()}/tmp`;
|
||||
let qr_svg = imageQr(base64, { type: "svg", margin: 4 });
|
||||
qr_svg.pipe(require("fs").createWriteStream(`${path}/qr.svg`));
|
||||
console.log(`⚡ Recuerda que el QR se actualiza cada minuto ⚡'`);
|
||||
console.log(`⚡ Actualiza F5 el navegador para mantener el mejor QR⚡`);
|
||||
};
|
||||
}
|
||||
|
||||
export default WsTransporter;
|
||||
28
src/infrastructure/router/index.ts
Normal file
28
src/infrastructure/router/index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { readdirSync } from "fs";
|
||||
import express, { Router } from "express";
|
||||
const router: Router = Router();
|
||||
|
||||
const PATH_ROUTES = __dirname;
|
||||
|
||||
function removeExtension(fileName: string): string {
|
||||
const cleanFileName = <string>fileName.split(".").shift();
|
||||
return cleanFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param file tracks.ts
|
||||
*/
|
||||
function loadRouter(file: string): void {
|
||||
const name = removeExtension(file);
|
||||
if (name !== "index") {
|
||||
import(`./${file}`).then((routerModule) => {
|
||||
console.log("cargado", name);
|
||||
router.use(`/${name}`, routerModule.router);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
readdirSync(PATH_ROUTES).filter((file) => loadRouter(file));
|
||||
|
||||
export default router;
|
||||
12
src/infrastructure/router/lead.route.ts
Normal file
12
src/infrastructure/router/lead.route.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import express, { Router } from "express";
|
||||
import LeadCtrl from "../controller/lead.ctrl";
|
||||
import container from "../ioc";
|
||||
const router: Router = Router();
|
||||
|
||||
/**
|
||||
* http://localhost/lead POST
|
||||
*/
|
||||
const leadCtrl: LeadCtrl = container.get("lead.ctrl");
|
||||
router.post("/", leadCtrl.sendCtrl);
|
||||
|
||||
export { router };
|
||||
Reference in New Issue
Block a user