Skip to content

Commit 2cb3de7

Browse files
committed
feat(bot): implement report and cancel commands for user moderation
- Add `ReportCommand` class: - Introduced functionality for users to report messages to group admins. - Reports are sent only to admins without publicly tagging them, maintaining privacy. - `report` method: - Allows users to report a message by replying to it. - Gathers reported user details, message link, and notifier information. - Collects admin mentions and prepares a formatted notification message. - Sends a confirmation message to the reporter about the report being queued. - Adds a 5-minute delay before sending the report to admins, allowing time for cancellation. - Stores pending reports in `pendingReports` using user IDs as keys and timeout IDs as values. - `cancel` method: - Enables reporters to cancel their pending reports. - Checks if a report is queued for the user and clears the associated timeout. - Notifies the user if their report was successfully canceled or if no pending report exists. - Enhancements: - Improved user experience with detailed notifications. - Ensured admins receive concise and well-formatted reports with clickable links to reported messages. - Prevents spamming admins with immediate reports by introducing a delay mechanism. - Pending Reports: - Maintains a map of pending reports to manage and track active report requests. - Supports cleanup by removing processed or canceled reports. - Future Improvements: - Extend moderation tools for admins, such as automated actions based on reports. - Add analytics or tracking for repeated offenses.
1 parent f0d1a87 commit 2cb3de7

1 file changed

Lines changed: 80 additions & 0 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { Context } from 'grammy';
2+
import { BotReply } from '../../../utils/chat/BotReply';
3+
4+
export class ReportCommand {
5+
// Store pending reports with user IDs as keys
6+
private static pendingReports = new Map<number, number>();
7+
8+
/**
9+
* Sends a report to the group admins without publicly tagging them.
10+
* If the report is canceled before notification, the message will be deleted.
11+
*
12+
* @param ctx - The context object containing information about the incoming update.
13+
*/
14+
static async report(ctx: Context) {
15+
const reply = new BotReply(ctx);
16+
17+
// Ensure the report command is a reply to another message
18+
const reportedMessage = ctx.message?.reply_to_message;
19+
if (!reportedMessage || !reportedMessage.from) {
20+
await ctx.reply('Please use the /report command by replying to the message you want to report.');
21+
return;
22+
}
23+
24+
// Get reported user details
25+
const reportedUser = reportedMessage.from;
26+
const reportedUserName = reportedUser.first_name;
27+
const reportedUserId = reportedUser.id;
28+
const chatId = Math.abs(ctx.chat!.id + 1000000000000);
29+
const messageLink = `https://t.me/c/${chatId}/${reportedMessage.message_id}`;
30+
// Collect secret mentions of all admins
31+
const admins = await ctx.api.getChatAdministrators(ctx.chat!.id);
32+
const adminMentions = admins
33+
.filter((admin) => !admin.user.is_bot)
34+
.map((admin) => `<a href="tg://user?id=${admin.user.id}"> </a>`)
35+
.join('');
36+
37+
// Format the report message for admins
38+
const reportMessage = `
39+
<b>🚨 Report Notification</b>
40+
- Reported User: ${reportedUserName} (ID: ${reportedUserId})
41+
- Reported by: @${ctx.from?.username || ctx.from?.first_name} (ID: ${ctx.from?.id})
42+
- Message Link: <a href="${messageLink}">Click here to view the message</a>
43+
`.trim();
44+
const finalMessage = `${reportMessage}`;
45+
// Notify the reporter
46+
await reply.replyToMessage(`${reportedUserName}${adminMentions}(${reportedUserId}) was reported to administrators.`);
47+
48+
// Send the report to admins only after a delay, allowing time for cancellation
49+
const delayForCancel = 300000; // 5 minutes (300,000 milliseconds) delay for cancellation
50+
const reportTimeout = setTimeout(async () => {
51+
for (const admin of admins) {
52+
if (admin.user.is_bot) continue;
53+
await ctx.api.sendMessage(admin.user.id, finalMessage, { parse_mode: 'HTML' });
54+
}
55+
// Remove the report from pendingReports after sending
56+
ReportCommand.pendingReports.delete(ctx.from!.id);
57+
}, delayForCancel);
58+
59+
// Store the report with user ID and the setTimeout ID for canceling
60+
ReportCommand.pendingReports.set(ctx.from!.id, Number(reportTimeout));
61+
}
62+
63+
/**
64+
* Cancels the pending report.
65+
* If the report is canceled, it will not be sent to the admins.
66+
*
67+
* @param ctx - The context object containing information about the incoming update.
68+
*/
69+
static async cancel(ctx: Context) {
70+
const reply = new BotReply(ctx);
71+
const reportTimeout = ReportCommand.pendingReports.get(ctx.from!.id);
72+
if (reportTimeout) {
73+
clearTimeout(reportTimeout);
74+
ReportCommand.pendingReports.delete(ctx.from!.id);
75+
await reply.textReply('Your report has been canceled and will not be sent to the admins.');
76+
} else {
77+
await reply.textReply('There is no report to cancel.');
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)