request-bot/index.js

263 lines
12 KiB
JavaScript
Raw Normal View History

2025-01-07 12:02:18 -05:00
require('dotenv').config();
const { Telegraf, Markup } = require('telegraf');
const fs = require('fs');
const moment = require('moment');
const bot = new Telegraf(process.env.BOT_TOKEN);
const questions = [
"Are you submitting an app (1) or a module (2)? You may only respond with 1 or 2.",
"What is the name of the app or module?",
2025-01-07 18:02:13 -05:00
"Where can I find an icon of the app or module? If there is none, simply enter https://nothing.com",
"What is the GitHub/Source of the app or module? If there is none, simply enter https://nothing.com",
2025-01-07 12:02:18 -05:00
"Do you have any other comments?"
];
const labels = ["type", "name", "icon", "source", "comments"];
let userResponses = {};
const userSummary = {};
if (fs.existsSync('responses.json')) {
const data = fs.readFileSync('responses.json');
userResponses = JSON.parse(data);
}
bot.use((ctx, next) => {
console.log(ctx.message);
return next();
});
bot.start((ctx) => ctx.reply(`Hey there! You can call me RequestBot. Did you know I'm FOSS?! Use /help if you need any :)`));
bot.help((ctx) => {
let helpMessage = '<b>Commands:</b>\n\n' +
'/start - Start bot (not really useful)\n' +
'/help - Get help (you know this one!)\n' +
'/new - Start a new request\n' +
'/status - Check the status of your requests\n' +
'/check [requestid] - View details of a specific request\n\n';
if (ctx.from.id.toString() === process.env.ADMIN_ID) {
helpMessage += '<b>Admin Commands:</b>\n\n' +
'/requests - List all requests\n' +
'/view [id] - View details of a user and their requests\n' +
'/view [userid] [requestid] - View details of a user\'s request\n' +
'/accept [userid] [requestid] - Accept a request\n' +
'/decline [userid] [requestid] - Decline a request\n';
}
ctx.replyWithHTML(helpMessage);
});
bot.command('new', (ctx) => {
const chatId = ctx.chat.id;
if (!userResponses[chatId]) {
userResponses[chatId] = [];
}
userResponses[chatId].push({
step: 0,
responses: {},
timestamp: Math.floor(Date.now() / 1000),
username: ctx.from.username,
firstName: ctx.from.first_name,
status: 'pending'
});
ctx.reply(questions[0]);
fs.writeFileSync('responses.json', JSON.stringify(userResponses, null, 2));
});
bot.command('status', (ctx) => {
const chatId = ctx.chat.id;
if (userResponses[chatId] && userResponses[chatId].length > 0) {
let responseText = '<b>My Requests:</b>\n\n';
userResponses[chatId].forEach((request, index) => {
2025-01-07 18:43:20 -05:00
const type = request.responses.type === '1' ? 'App' : 'Module';
responseText += `[${index + 1}] ${request.status.toUpperCase()} - ${type}: ${request.responses.name || 'N/A'}\n`;
2025-01-07 12:02:18 -05:00
});
responseText += '\nUse /check [id] to view the request.';
ctx.replyWithHTML(responseText);
} else {
ctx.reply(`You don't have any requests to view.`);
}
});
bot.command('check', (ctx) => {
const text = ctx.message.text;
const args = text.split(' ');
if (args.length === 2) {
const chatId = ctx.chat.id;
const requestId = parseInt(args[1]) - 1;
if (userResponses[chatId] && userResponses[chatId][requestId]) {
const request = userResponses[chatId][requestId];
2025-01-07 18:43:20 -05:00
const type = request.responses.type === '1' ? 'App' : 'Module';
2025-01-07 12:02:18 -05:00
let responseText = `<b>My Request - #${requestId + 1}</b>\n\n`;
responseText += `Timestamp: ${moment.unix(request.timestamp).format('MMMM Do YYYY, h:mm:ss a')}\n`;
responseText += `Status: ${request.status}\n\n`;
responseText += `Request:\n\n`;
for (const [key, value] of Object.entries(request.responses)) {
2025-01-07 18:43:20 -05:00
const displayValue = key === 'type' ? type : value;
responseText += `${key.charAt(0).toUpperCase() + key.slice(1)}: ${displayValue || 'N/A'}\n`;
2025-01-07 12:02:18 -05:00
}
ctx.replyWithHTML(responseText);
} else {
ctx.reply('Invalid request ID.');
}
} else {
ctx.reply('Invalid command. Try doing /check [requestid].');
}
});
bot.command('requests', (ctx) => {
if (ctx.from.id.toString() === process.env.ADMIN_ID) {
if (Object.keys(userResponses).length === 0) {
ctx.reply(`Sorry, there aren't any requests yet!`);
return;
}
let responseText = '<b>Requests:</b>\n\n';
let index = 1;
let hasPendingRequests = false;
for (const [chatId, requests] of Object.entries(userResponses)) {
const pendingRequests = requests.filter(request => request.status === 'pending').length;
if (pendingRequests > 0) {
2025-01-07 18:43:20 -05:00
const type = requests[0].responses.type === '1' ? 'App' : 'Module';
responseText += `[${index}] <b>${pendingRequests}</b> new requests from @${requests[0].username} (${type})\n`;
2025-01-07 12:02:18 -05:00
userSummary[index] = { chatId, username: requests[0].username, totalRequests: requests.length, pendingRequests };
index++;
hasPendingRequests = true;
}
}
if (!hasPendingRequests) {
ctx.reply(`Sorry, there aren't any requests yet!`);
} else {
responseText += '\nPlease select a user to view with /view [id].';
ctx.replyWithHTML(responseText);
}
} else {
ctx.reply(`Hey, you aren't allowed to use that command!`);
}
});
bot.command('view', (ctx) => {
const text = ctx.message.text;
const args = text.split(' ');
if (args.length === 2 && ctx.from.id.toString() === process.env.ADMIN_ID && userSummary[args[1]]) {
const summary = userSummary[args[1]];
const lastRequest = userResponses[summary.chatId][userResponses[summary.chatId].length - 1];
const lastRequestTime = moment.unix(lastRequest.timestamp).fromNow();
let responseText = `<b>@${summary.username}</b>\nUser ID: ${summary.chatId}\n\n`;
responseText += `Requests Sent (Lifetime): ${summary.totalRequests}\n`;
responseText += `New Requests (Pending): ${summary.pendingRequests}\n`;
responseText += `Request Last Sent: ${lastRequestTime}\n\n`;
userResponses[summary.chatId].forEach((request, index) => {
if (request.status === 'pending') {
2025-01-07 18:43:20 -05:00
const type = request.responses.type === '1' ? 'App' : 'Module';
responseText += `[${index + 1}] ${type}: ${request.responses.name || 'N/A'}\n`;
2025-01-07 12:02:18 -05:00
}
});
ctx.replyWithHTML(responseText);
} else if (args.length === 3 && ctx.from.id.toString() === process.env.ADMIN_ID) {
const chatId = args[1];
const requestId = parseInt(args[2]) - 1;
if (userResponses[chatId] && userResponses[chatId][requestId]) {
const request = userResponses[chatId][requestId];
2025-01-07 18:43:20 -05:00
const type = request.responses.type === '1' ? 'App' : 'Module';
2025-01-07 12:02:18 -05:00
let responseText = `<b>Request from @${request.username}</b>\n\n`;
responseText += `Timestamp: ${moment.unix(request.timestamp).format('MMMM Do YYYY, h:mm:ss a')}\n`;
responseText += `Status: ${request.status}\n\n`;
responseText += `Request:\n\n`;
for (const [key, value] of Object.entries(request.responses)) {
2025-01-07 18:43:20 -05:00
const displayValue = key === 'type' ? type : value;
responseText += `${key.charAt(0).toUpperCase() + key.slice(1)}: ${displayValue || 'N/A'}\n`;
2025-01-07 12:02:18 -05:00
}
responseText += `\nTo accept this request, use the command:\n<code>/accept ${chatId} ${requestId + 1}</code>\n`;
responseText += `To decline this request, use the command:\n<code>/decline ${chatId} ${requestId + 1}</code>`;
2025-01-07 12:02:18 -05:00
ctx.replyWithHTML(responseText);
} else {
ctx.reply('Invalid user ID or request ID.');
}
} else {
ctx.reply(`You entered an invalid command or aren't allowed to use this!`);
}
});
bot.command('accept', (ctx) => {
const text = ctx.message.text;
const args = text.split(' ');
if (args.length === 3 && ctx.from.id.toString() === process.env.ADMIN_ID) {
const chatId = args[1];
const requestId = parseInt(args[2]) - 1;
if (userResponses[chatId] && userResponses[chatId][requestId]) {
userResponses[chatId][requestId].status = 'accepted';
fs.writeFileSync('responses.json', JSON.stringify(userResponses, null, 2));
ctx.reply(`Request ${requestId + 1} from @${userResponses[chatId][requestId].username} has been accepted.`);
} else {
ctx.reply('Invalid user ID or request ID.');
}
} else {
ctx.reply(`You entered an invalid command or aren't allowed to use this!`);
}
});
bot.command('decline', (ctx) => {
const text = ctx.message.text;
const args = text.split(' ');
if (args.length === 3 && ctx.from.id.toString() === process.env.ADMIN_ID) {
const chatId = args[1];
const requestId = parseInt(args[2]) - 1;
if (userResponses[chatId] && userResponses[chatId][requestId]) {
userResponses[chatId][requestId].status = 'declined';
fs.writeFileSync('responses.json', JSON.stringify(userResponses, null, 2));
ctx.reply(`Request ${requestId + 1} from @${userResponses[chatId][requestId].username} has been declined.`);
} else {
ctx.reply('Invalid user ID or request ID.');
}
} else {
ctx.reply(`You entered an invalid command or aren't allowed to use this!`);
}
});
bot.on('text', (ctx) => {
const chatId = ctx.chat.id;
const text = ctx.message.text;
if (userResponses[chatId] && userResponses[chatId].length > 0 && userResponses[chatId][userResponses[chatId].length - 1].step < questions.length) {
const currentRequest = userResponses[chatId][userResponses[chatId].length - 1];
if (currentRequest.step === 0 && (text !== '1' && text !== '2')) {
ctx.reply('Please respond with either 1 or 2.');
return;
}
if (currentRequest.step === 3 && !text.match(/https?:\/\/[^\s]+/)) {
ctx.reply('Please provide a valid link. A link should look like: https://example.com');
return;
}
currentRequest.responses[labels[currentRequest.step]] = text;
currentRequest.step += 1;
if (currentRequest.step < questions.length) {
ctx.reply(questions[currentRequest.step]);
} else {
fs.writeFileSync('responses.json', JSON.stringify(userResponses, null, 2));
ctx.reply('Thank you for your responses!');
}
} else if (text.startsWith('/')) {
ctx.reply('Please complete the current process by answering the questions.');
} else {
ctx.reply(`Why are you talking to me? Create a request and stop blabbing about "${text}"`);
}
});
bot.action(/setstatus_(.+)/, (ctx) => {
if (ctx.from.id.toString() === process.env.ADMIN_ID) {
const [chatId, requestIndex, status] = ctx.match[1].split('_');
userResponses[chatId][requestIndex].status = status;
fs.writeFileSync('responses.json', JSON.stringify(userResponses, null, 2));
ctx.reply(`Status of request ${parseInt(requestIndex) + 1} from ${userResponses[chatId][requestIndex].firstName} (@${userResponses[chatId][requestIndex].username}) has been updated to ${status}.`);
} else {
ctx.reply(`Hey, you aren't allowed to use that command!`);
}
});
bot.launch().then(() => {
console.log('Bot is up');
}).catch(err => {
console.error('FAIL:', err);
});