You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

261 lines
8.1 KiB
TypeScript

import express from 'express';
import axios from 'axios';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
const API_URL = process.env.API_URL;
const INSTANCE_NAME = process.env.INSTANCE_NAME;
const API_KEY = process.env.API_KEY;
const WEBHOOK_URL = process.env.WEBHOOK_URL;
const COMMUNITY_ID = process.env.COMMUNITY_ID;
if (!API_URL || !INSTANCE_NAME || !API_KEY || !WEBHOOK_URL || !COMMUNITY_ID) {
throw new Error('Required environment variables are not defined.');
}
// Store community and group information
const linkedGroups: Set<string> = new Set();
// Create an Express app
const app = express();
app.use(express.json());
// Fetch all groups and identify the community and linked groups
async function fetchGroups() {
try {
const response = await axios.get(`${API_URL}/group/fetchAllGroups/${INSTANCE_NAME}?getParticipants=false`, {
headers: {
apikey: API_KEY,
},
});
console.log('API Response:', response.data); // Log the full response
// Check if the response is an array of groups
if (Array.isArray(response.data)) {
for (const group of response.data) {
if (group.id === COMMUNITY_ID) {
// This is the community
console.log(`Community ID: ${COMMUNITY_ID}`);
} else if (group.linkedParent === COMMUNITY_ID) {
// This is a group linked to the community
linkedGroups.add(group.id);
console.log(`Linked Group ID: ${group.id}`);
}
}
} else {
console.error('Unexpected response format:', response.data);
}
} catch (error) {
console.error('Error fetching groups:', error.response ? error.response.data : error.message);
}
}
// Add the bot to a new group
async function addBotToGroup(groupId: string) {
try {
await axios.post(`${API_URL}/group/invite`, {
groupId,
participants: ['your-bot-phone-number'], // Replace with your bot's phone number
}, {
headers: {
'Content-Type': 'application/json',
apikey: API_KEY,
},
});
console.log(`Bot added to group: ${groupId}`);
} catch (error) {
console.error('Error adding bot to group:', error);
}
}
// Webhook endpoint
app.post('/webhook', (req, res) => {
const event = req.body;
console.log('Received event:', JSON.stringify(event, null, 2)); // Log the full event
// Handle the event
if (event.event === 'messages.upsert') {
const messageData = event.data;
// Ignore messages sent by the bot itself
// if (messageData.key.fromMe) {
// console.log('Ignoring message sent by the bot itself');
// return res.status(200).send('OK');
// }
// Handle the message
handleMessage(messageData);
} else if (event.event === 'group_create' && event.data.parentGroupId === COMMUNITY_ID) {
// A new group was created in the community
const groupId = event.data.groupId;
linkedGroups.add(groupId);
addBotToGroup(groupId);
}
res.status(200).send('OK');
});
// Handle incoming messages
function handleMessage(messageData: any) {
// console.log('Incoming message data:', JSON.stringify(messageData, null, 2)); // Log the full message data
const body = messageData.message?.conversation;
const sender = messageData.key.remoteJid;
const groupId = messageData.key.remoteJid; // Group ID for community messages
// Check if the message is from a group linked to the community
if (groupId && linkedGroups.has(groupId) && body) {
// Parse the command
if (body.startsWith('/tarea')) {
// Remove the "/tarea" prefix and trim any extra spaces
const command = body.replace('/tarea', '').trim();
// Split the remaining command into action and arguments
const [action, ...args] = command.split(' ');
console.log('Parsed action:', action); // Log the action
console.log('Parsed args:', args); // Log the arguments
const description = args.join(' ');
console.log('Description:', description); // Log the description
// Extract assigned user (if any)
const assignedUserMatch = description.match(/@\w+/);
const assignedUser = assignedUserMatch ? assignedUserMatch[0] : null;
// Extract due date (if any)
const dueDateMatch = description.match(/\d{4}-\d{2}-\d{2}/);
const dueDate = dueDateMatch ? dueDateMatch[0] : null;
// Remove the assigned user and due date from the description
const cleanDescription = description
.replace(/@\w+/g, '') // Remove assigned user
.replace(/\d{4}-\d{2}-\d{2}/g, '') // Remove due date
.trim(); // Remove extra spaces
if (action === 'nueva') {
// If no user is assigned, default to the sender
const finalAssignedUser = assignedUser || `@${sender.split('@')[0]}`;
createTask(sender, cleanDescription, finalAssignedUser, dueDate);
} else if (action === 'asignar') {
const taskId = args[0];
if (assignedUser) {
assignTask(sender, taskId, assignedUser);
} else {
sendMessage(sender, 'Debes mencionar a un usuario para asignar la tarea. Ejemplo: /tarea asignar 1 @usuario');
}
} else if (action === 'completar') {
const taskId = args[0];
completeTask(sender, taskId);
} else {
sendMessage(sender, 'Acción no reconocida. Usa /tarea nueva, /tarea asignar, o /tarea completar.');
}
}
}
}
// Create a new task
function createTask(sender: string, description: string, assignedUser?: string, dueDate?: string) {
const task = {
id: tasks.length + 1,
description,
assignedTo: assignedUser || null,
dueDate: dueDate || null,
completed: false,
};
tasks.push(task);
sendMessage(sender, `Tarea creada: ${task.id} - ${task.description}${assignedUser ? ` asignada a ${assignedUser}` : ''}${dueDate ? ` para el ${dueDate}` : ''}`);
}
// Assign a task
function assignTask(sender: string, taskId: string, assignedUser: string) {
const task = tasks.find((t) => t.id === parseInt(taskId));
if (task) {
task.assignedTo = assignedUser;
sendMessage(sender, `Tarea ${taskId} asignada a ${assignedUser}`);
} else {
sendMessage(sender, `Tarea ${taskId} no encontrada`);
}
}
// Mark a task as completed
function completeTask(sender: string, taskId: string) {
const task = tasks.find((t) => t.id === parseInt(taskId));
if (task) {
task.completed = true;
sendMessage(sender, `Tarea ${taskId} marcada como completada`);
} else {
sendMessage(sender, `Tarea ${taskId} no encontrada`);
}
}
// Send a message
async function sendMessage(phone: string, message: string) {
try {
await axios.post(`${API_URL}/message/sendText/${INSTANCE_NAME}`, {
number: phone,
text: message,
}, {
headers: {
'Content-Type': 'application/json',
apikey: API_KEY,
},
});
} catch (error) {
console.error('Error sending message:', error);
}
}
// In-memory task storage
const tasks: any[] = [];
// Start the webhook server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Webhook server running on port ${PORT}`);
});
// Configure the webhook in Evolution API
async function configureWebhook() {
try {
const response = await axios.post(
`${API_URL}/webhook/set/${INSTANCE_NAME}`,
{
webhook: {
url: WEBHOOK_URL, // Use the environment variable
enabled: true,
webhook_by_events: true,
webhook_base64: true,
events: [
'MESSAGES_UPSERT', // New or updated messages
'GROUPS_UPSERT', // New or updated groups
'GROUP_PARTICIPANTS_UPDATE', // Group participant changes
'GROUP_UPDATE', // Group metadata changes (optional)
],
},
},
{
headers: {
'Content-Type': 'application/json',
apikey: API_KEY,
},
}
);
console.log('Webhook configured successfully:', response.data);
} catch (error) {
console.error('Error configuring webhook:', error.response ? error.response.data : error.message);
}
}
// Fetch groups and configure the webhook when the bot starts
async function startBot() {
await fetchGroups();
await configureWebhook();
}
startBot();