mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-18 19:59:20 +00:00
Feat. Api send
This commit is contained in:
92
backend/src/controllers/ApiController.ts
Normal file
92
backend/src/controllers/ApiController.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { Request, Response } from "express";
|
||||
import * as Yup from "yup";
|
||||
import AppError from "../errors/AppError";
|
||||
import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp";
|
||||
import SetTicketMessagesAsRead from "../helpers/SetTicketMessagesAsRead";
|
||||
import Message from "../models/Message";
|
||||
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
||||
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
|
||||
import ShowTicketService from "../services/TicketServices/ShowTicketService";
|
||||
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
|
||||
import CheckContactNumber from "../services/WbotServices/CheckNumber";
|
||||
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
|
||||
import SendWhatsAppMedia from "../services/WbotServices/SendWhatsAppMedia";
|
||||
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
|
||||
|
||||
type MessageData = {
|
||||
body: string;
|
||||
fromMe: boolean;
|
||||
read: boolean;
|
||||
quotedMsg?: Message;
|
||||
};
|
||||
|
||||
interface ContactData {
|
||||
number: string;
|
||||
}
|
||||
|
||||
const createContact = async (newContact: string) => {
|
||||
await CheckIsValidContact(newContact);
|
||||
|
||||
const validNumber: any = await CheckContactNumber(newContact);
|
||||
|
||||
const profilePicUrl = await GetProfilePicUrl(validNumber);
|
||||
|
||||
const number = validNumber;
|
||||
|
||||
const contactData = {
|
||||
name: `${number}`,
|
||||
number,
|
||||
profilePicUrl,
|
||||
isGroup: false
|
||||
};
|
||||
|
||||
const contact = await CreateOrUpdateContactService(contactData);
|
||||
|
||||
const defaultWhatsapp = await GetDefaultWhatsApp();
|
||||
|
||||
const createTicket = await FindOrCreateTicketService(
|
||||
contact,
|
||||
defaultWhatsapp.id,
|
||||
1
|
||||
);
|
||||
|
||||
const ticket = await ShowTicketService(createTicket.id);
|
||||
|
||||
SetTicketMessagesAsRead(ticket);
|
||||
|
||||
return ticket;
|
||||
};
|
||||
|
||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||
const newContact: ContactData = req.body;
|
||||
const { body, quotedMsg }: MessageData = req.body;
|
||||
const medias = req.files as Express.Multer.File[];
|
||||
|
||||
newContact.number = newContact.number.replace("-", "").replace(" ", "");
|
||||
|
||||
const schema = Yup.object().shape({
|
||||
number: Yup.string()
|
||||
.required()
|
||||
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
|
||||
});
|
||||
|
||||
try {
|
||||
await schema.validate(newContact);
|
||||
} catch (err: any) {
|
||||
throw new AppError(err.message);
|
||||
}
|
||||
|
||||
const contactAndTicket = await createContact(newContact.number);
|
||||
|
||||
if (medias) {
|
||||
await Promise.all(
|
||||
medias.map(async (media: Express.Multer.File) => {
|
||||
await SendWhatsAppMedia({ body, media, ticket: contactAndTicket });
|
||||
})
|
||||
);
|
||||
} else {
|
||||
await SendWhatsAppMessage({ body, ticket: contactAndTicket, quotedMsg });
|
||||
}
|
||||
|
||||
return res.send();
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import { QueryInterface } from "sequelize";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkInsert(
|
||||
"Settings",
|
||||
[
|
||||
{
|
||||
key: "userApiToken",
|
||||
value: uuidv4(),
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}
|
||||
],
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkDelete("Settings", {});
|
||||
}
|
||||
};
|
||||
39
backend/src/middleware/isAuthApi.ts
Normal file
39
backend/src/middleware/isAuthApi.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
|
||||
import AppError from "../errors/AppError";
|
||||
import ListSettingByValueService from "../services/SettingServices/ListSettingByValueService";
|
||||
|
||||
const isAuthApi = async (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<void> => {
|
||||
const authHeader = req.headers.authorization;
|
||||
|
||||
if (!authHeader) {
|
||||
throw new AppError("ERR_SESSION_EXPIRED", 401);
|
||||
}
|
||||
|
||||
const [, token] = authHeader.split(" ");
|
||||
|
||||
try {
|
||||
const getToken = await ListSettingByValueService(token);
|
||||
if (!getToken) {
|
||||
throw new AppError("ERR_SESSION_EXPIRED", 401);
|
||||
}
|
||||
|
||||
if (getToken.value !== token) {
|
||||
throw new AppError("ERR_SESSION_EXPIRED", 401);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
throw new AppError(
|
||||
"Invalid token. We'll try to assign a new one on next request",
|
||||
403
|
||||
);
|
||||
}
|
||||
|
||||
return next();
|
||||
};
|
||||
|
||||
export default isAuthApi;
|
||||
14
backend/src/routes/apiRoutes.ts
Normal file
14
backend/src/routes/apiRoutes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import express from "express";
|
||||
import multer from "multer";
|
||||
import uploadConfig from "../config/upload";
|
||||
|
||||
import * as ApiController from "../controllers/ApiController";
|
||||
import isAuthApi from "../middleware/isAuthApi";
|
||||
|
||||
const upload = multer(uploadConfig);
|
||||
|
||||
const ApiRoutes = express.Router();
|
||||
|
||||
ApiRoutes.post("/send", isAuthApi, upload.array("medias"), ApiController.index);
|
||||
|
||||
export default ApiRoutes;
|
||||
@@ -10,6 +10,7 @@ import messageRoutes from "./messageRoutes";
|
||||
import whatsappSessionRoutes from "./whatsappSessionRoutes";
|
||||
import queueRoutes from "./queueRoutes";
|
||||
import quickAnswerRoutes from "./quickAnswerRoutes";
|
||||
import apiRoutes from "./apiRoutes";
|
||||
|
||||
const routes = Router();
|
||||
|
||||
@@ -23,5 +24,6 @@ routes.use(messageRoutes);
|
||||
routes.use(whatsappSessionRoutes);
|
||||
routes.use(queueRoutes);
|
||||
routes.use(quickAnswerRoutes);
|
||||
routes.use("/api/messages", apiRoutes);
|
||||
|
||||
export default routes;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import AppError from "../../errors/AppError";
|
||||
import Setting from "../../models/Setting";
|
||||
|
||||
interface Response {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
const ListSettingByKeyService = async (
|
||||
value: string
|
||||
): Promise<Response | undefined> => {
|
||||
const settings = await Setting.findOne({
|
||||
where: { value }
|
||||
});
|
||||
|
||||
if (!settings) {
|
||||
throw new AppError("ERR_NO_API_TOKEN_FOUND", 404);
|
||||
}
|
||||
|
||||
return { key: settings.key, value: settings.value };
|
||||
};
|
||||
|
||||
export default ListSettingByKeyService;
|
||||
@@ -7,24 +7,28 @@ import Ticket from "../../models/Ticket";
|
||||
interface Request {
|
||||
media: Express.Multer.File;
|
||||
ticket: Ticket;
|
||||
body?: string;
|
||||
}
|
||||
|
||||
const SendWhatsAppMedia = async ({
|
||||
media,
|
||||
ticket
|
||||
ticket,
|
||||
body
|
||||
}: Request): Promise<WbotMessage> => {
|
||||
try {
|
||||
const wbot = await GetTicketWbot(ticket);
|
||||
|
||||
const newMedia = MessageMedia.fromFilePath(media.path);
|
||||
|
||||
const sentMessage = await wbot.sendMessage(
|
||||
`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
|
||||
newMedia,
|
||||
{ sendAudioAsVoice: true }
|
||||
{
|
||||
caption: body,
|
||||
sendAudioAsVoice: true
|
||||
}
|
||||
);
|
||||
|
||||
await ticket.update({ lastMessage: media.filename });
|
||||
await ticket.update({ lastMessage: body || media.filename });
|
||||
|
||||
fs.unlinkSync(media.path);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user