Skip to content

Commit 2b25d8a

Browse files
committed
feat: Added ReplyToBot decorator, RateLimit decorator, and jokeMessage function; updated UserCommands class to use ReplyToBot decorator; modified createDecorator function to handle errors; added RateLimitConfig type; updated ChatInfo class to remove RateLimiter
1 parent 10a9dfa commit 2b25d8a

File tree

14 files changed

+192
-47
lines changed

14 files changed

+192
-47
lines changed

src/bot/commands/admin/AdminCommands.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import { GroupSettingsService } from '../../service/admin/Welcome';
1313
import { OnlyAdminsCanUse } from '../../../decorators/User';
1414
import { RequireReply, RestrictToGroupChats } from '../../../decorators/Context';
1515
import { EnsureUserAndGroup } from '../../../decorators/Database';
16-
import { BotIsAdmin } from '../../../decorators/Bot';
16+
import { BotIsAdmin, ReplyToBot } from '../../../decorators/Bot';
1717
export class AdminCommands {
1818
/** Approved Commands */
1919
@RestrictToGroupChats()
20+
@ReplyToBot()
2021
@BotIsAdmin()
2122
@OnlyAdminsCanUse()
2223
@RequireReply()
@@ -45,6 +46,7 @@ export class AdminCommands {
4546
}
4647

4748
@RestrictToGroupChats()
49+
@ReplyToBot()
4850
@BotIsAdmin()
4951
@OnlyAdminsCanUse()
5052
@RequireReply()
@@ -68,6 +70,7 @@ export class AdminCommands {
6870
}
6971

7072
@RestrictToGroupChats()
73+
@ReplyToBot()
7174
@BotIsAdmin()
7275
@OnlyAdminsCanUse()
7376
@EnsureUserAndGroup()
@@ -91,6 +94,7 @@ export class AdminCommands {
9194
}
9295
/** Ban Commands */
9396
@RestrictToGroupChats()
97+
@ReplyToBot()
9498
@BotIsAdmin()
9599
@OnlyAdminsCanUse()
96100
@RequireReply()
@@ -107,6 +111,7 @@ export class AdminCommands {
107111
}
108112
}
109113
@RestrictToGroupChats()
114+
@ReplyToBot()
110115
@BotIsAdmin()
111116
@OnlyAdminsCanUse()
112117
@RequireReply()
@@ -122,6 +127,7 @@ export class AdminCommands {
122127
}
123128
/** Warn Commands */
124129
@RestrictToGroupChats()
130+
@ReplyToBot()
125131
@BotIsAdmin()
126132
@OnlyAdminsCanUse()
127133
@RequireReply()
@@ -140,6 +146,7 @@ export class AdminCommands {
140146
}
141147
}
142148
@RestrictToGroupChats()
149+
@ReplyToBot()
143150
@BotIsAdmin()
144151
@OnlyAdminsCanUse()
145152
@RequireReply()
@@ -157,6 +164,7 @@ export class AdminCommands {
157164
}
158165
}
159166
@RestrictToGroupChats()
167+
@ReplyToBot()
160168
@BotIsAdmin()
161169
@EnsureUserAndGroup()
162170
static async warns(ctx: Context) {
@@ -174,6 +182,7 @@ export class AdminCommands {
174182
}
175183
}
176184
@RestrictToGroupChats()
185+
@ReplyToBot()
177186
@BotIsAdmin()
178187
@OnlyAdminsCanUse()
179188
@EnsureUserAndGroup()
@@ -185,6 +194,7 @@ export class AdminCommands {
185194
}
186195
/** Mute Commands */
187196
@RestrictToGroupChats()
197+
@ReplyToBot()
188198
@BotIsAdmin()
189199
@OnlyAdminsCanUse()
190200
@RequireReply()
@@ -196,6 +206,7 @@ export class AdminCommands {
196206
return await reply.textReply(message);
197207
}
198208
@RestrictToGroupChats()
209+
@ReplyToBot()
199210
@BotIsAdmin()
200211
@OnlyAdminsCanUse()
201212
@RequireReply()
@@ -208,42 +219,33 @@ export class AdminCommands {
208219
}
209220
/** Admin Command */
210221
@RestrictToGroupChats()
222+
@ReplyToBot()
211223
@BotIsAdmin()
212224
@OnlyAdminsCanUse()
213225
@RequireReply()
214226
@EnsureUserAndGroup()
215227
@Catch()
216228
static async grant(ctx: Context) {
217229
const reply = new BotReply(ctx);
218-
const chatInfo = new ChatInfo(ctx);
219-
const isOwner = await chatInfo.userIsOwner();
220-
if (isOwner) {
221-
await reply.textReply('The owner of the chat cannot be granted administrator privileges.');
222-
return;
223-
}
224230
const grantUser = await AdminService.grant(ctx);
225231
await reply.textReply(grantUser);
226232
}
227233
@RestrictToGroupChats()
234+
@ReplyToBot()
228235
@BotIsAdmin()
229236
@OnlyAdminsCanUse()
230237
@RequireReply()
231238
@EnsureUserAndGroup()
232239
@Catch()
233240
static async revoke(ctx: Context) {
234241
const reply = new BotReply(ctx);
235-
const chatInfo = new ChatInfo(ctx);
236-
const isOwner = await chatInfo.userIsOwner();
237-
if (isOwner) {
238-
await reply.textReply("You cannot revoke the owner's rights.");
239-
return;
240-
}
241242
const revokeUser = await AdminService.revoke(ctx);
242243
await reply.textReply(revokeUser);
243244
}
244245

245246
/** BlackList Command */
246247
@RestrictToGroupChats()
248+
@ReplyToBot()
247249
@BotIsAdmin()
248250
@OnlyAdminsCanUse()
249251
@EnsureUserAndGroup()
@@ -284,6 +286,7 @@ Group Type: ${group?.type || 'Unknown'}
284286

285287
/** Add a Word to the Blacklist */
286288
@RestrictToGroupChats()
289+
@ReplyToBot()
287290
@BotIsAdmin()
288291
@OnlyAdminsCanUse()
289292
@EnsureUserAndGroup()
@@ -307,6 +310,7 @@ Group Type: ${group?.type || 'Unknown'}
307310

308311
/** Remove the Last Word from the Blacklist */
309312
@RestrictToGroupChats()
313+
@ReplyToBot()
310314
@BotIsAdmin()
311315
@OnlyAdminsCanUse()
312316
@EnsureUserAndGroup()
@@ -326,6 +330,7 @@ Group Type: ${group?.type || 'Unknown'}
326330

327331
/** Clear the Entire Blacklist */
328332
@RestrictToGroupChats()
333+
@ReplyToBot()
329334
@BotIsAdmin()
330335
@OnlyAdminsCanUse()
331336
@EnsureUserAndGroup()
@@ -343,6 +348,7 @@ Group Type: ${group?.type || 'Unknown'}
343348
}
344349
/** Pin Command */
345350
@RestrictToGroupChats()
351+
@ReplyToBot()
346352
@BotIsAdmin()
347353
@OnlyAdminsCanUse()
348354
@RequireReply()
@@ -356,6 +362,7 @@ Group Type: ${group?.type || 'Unknown'}
356362
await reply.textReply('The message has been pinned.');
357363
}
358364
@RestrictToGroupChats()
365+
@ReplyToBot()
359366
@BotIsAdmin()
360367
@OnlyAdminsCanUse()
361368
@RequireReply()
@@ -370,6 +377,7 @@ Group Type: ${group?.type || 'Unknown'}
370377
}
371378
/** Purge Command */
372379
@RestrictToGroupChats()
380+
@ReplyToBot()
373381
@BotIsAdmin()
374382
@OnlyAdminsCanUse()
375383
@RequireReply()
@@ -416,6 +424,7 @@ Group Type: ${group?.type || 'Unknown'}
416424
}
417425
/** Group Setting Command */
418426
@RestrictToGroupChats()
427+
@ReplyToBot()
419428
@BotIsAdmin()
420429
@OnlyAdminsCanUse()
421430
@EnsureUserAndGroup()

src/bot/commands/genearl/GeneralCommands.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { help, commands, start } from '../../../utils/jsons/botMessages.json';
55
import { ChatInfo } from '../../../utils/chat/ChatInfo';
66
import { DateCommand } from '../../service/general/date';
77
import * as BotInfoJson from '../../../../docs/BotInfo.json';
8+
import { ReplyToBot } from '../../../decorators/Bot';
9+
import { RestrictToGroupChats } from '../../../decorators/Context';
10+
import { jokeMessage } from '../../../utils';
811
/**
912
* Reason for lowercase command names:
1013
*
@@ -35,6 +38,7 @@ export class GeneralCommands {
3538
};
3639
}
3740
// === General Command Handlers ===
41+
@ReplyToBot()
3842
@Catch({
3943
message: 'Error displaying help message. Please try again later.',
4044
category: 'Bot',
@@ -47,6 +51,7 @@ export class GeneralCommands {
4751
await reply.markdownReply(sanitizedHelp);
4852
}
4953

54+
@ReplyToBot()
5055
@Catch({
5156
message: 'Error starting the bot. Please try again later.',
5257
category: 'Bot',
@@ -58,6 +63,7 @@ export class GeneralCommands {
5863
await reply.textReply(start);
5964
}
6065

66+
@ReplyToBot()
6167
@Catch({
6268
message: 'Error retrieving the date. Please try again later.',
6369
category: 'Bot',
@@ -92,6 +98,7 @@ export class GeneralCommands {
9298
const { commands } = GeneralCommands.getMessage(ctx);
9399
await reply.textReply(commands);
94100
}
101+
@ReplyToBot()
95102
@Catch({
96103
message: 'Error retrieving support contact information. Please try again later.',
97104
category: 'Bot',
@@ -138,34 +145,45 @@ This bot is designed to deliver fast and secure responses to users.
138145
await reply.markdownReply(botInfoMessage);
139146
}
140147
public static async shahin(ctx: Context) {
141-
await ctx.reply('دوستان.');
148+
const reply = new BotReply(ctx);
149+
const topicId = ctx.message?.reply_to_message?.message_thread_id!;
150+
await reply.sendToTopic('دوستان.', topicId);
142151
setTimeout(() => {
143-
return ctx.reply('بحث تخصصی.');
152+
return reply.sendToTopic('بحث تخصصی.', topicId);
144153
}, 2000);
145154
}
146155
private static aranState: Map<number, number> = new Map();
156+
147157
static async aran(ctx: Context) {
158+
const reply = new BotReply(ctx);
159+
const topicId = ctx.message?.reply_to_message?.message_thread_id!;
148160
const userId = ctx.from?.id;
149161
if (!userId) return;
150162

151163
const currentState = GeneralCommands.aranState.get(userId) || 0;
152164

153165
switch (currentState) {
154166
case 0:
155-
await ctx.reply('Aran mode: Activated.');
167+
await reply.sendToTopic('Aran mode: Activated.', topicId);
156168
GeneralCommands.aranState.set(userId, 1);
157169
break;
158170
case 1:
159-
await ctx.reply('رفرنس بده.');
171+
await reply.sendToTopic('رفرنس بده.', topicId);
160172
GeneralCommands.aranState.set(userId, 2);
161173
break;
162174
case 2:
163-
await ctx.reply('Aran mode: deActivated.');
175+
await reply.sendToTopic('Aran mode: deActivated.', topicId);
164176
GeneralCommands.aranState.set(userId, 0);
165177
break;
166178
default:
167179
GeneralCommands.aranState.set(userId, 0);
168180
break;
169181
}
170182
}
183+
static async joke(ctx: Context) {
184+
const reply = new BotReply(ctx);
185+
const topicId = ctx.message?.reply_to_message?.message_thread_id!;
186+
const randomMessage = jokeMessage();
187+
await reply.sendToTopic(randomMessage, topicId);
188+
}
171189
}

src/bot/commands/user/UserCommands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import { ChatInfo } from '../../../utils/chat/ChatInfo';
99
import { RequireReply, RestrictToGroupChats } from '../../../decorators/Context';
1010
import { EnsureUserAndGroup } from '../../../decorators/Database';
1111
import { escapeMarkdownV2 } from '../../../utils';
12+
import { ReplyToBot } from '../../../decorators/Bot';
1213
export class UserCommands {
1314
/**
1415
* Sends the rules of the group.
1516
* This command retrieves and sends the rules of the current group to the user.
1617
* It helps ensure that group members are aware of the guidelines for interaction.
1718
*/
19+
@ReplyToBot()
1820
@RestrictToGroupChats()
1921
@EnsureUserAndGroup('from')
2022
@Catch()
@@ -155,6 +157,7 @@ export class UserCommands {
155157
* This command allows users to report issues or ask questions directly to the group admins.
156158
* It’s typically used for urgent matters or when a user needs assistance.
157159
*/
160+
@ReplyToBot()
158161
@RestrictToGroupChats()
159162
@RequireReply()
160163
static async report(ctx: Context) {

src/bot/index.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import { GeneralCommands } from './commands/genearl/GeneralCommands';
77
import { UserCommands } from './commands/user/UserCommands';
88
import { AdminCommands } from './commands/admin/AdminCommands';
99
import * as http from 'http';
10-
import { SaveUserData } from '../decorators/Database';
11-
import { MessageValidator } from '../decorators/Context';
10+
import { EnsureUserAndGroup, SaveUserData } from '../decorators/Database';
11+
import { MessageValidator, RateLimit, RestrictToGroupChats } from '../decorators/Context';
12+
import { BotReply } from '../utils/chat/BotReply';
13+
import { ServiceProvider } from '../service/database/ServiceProvider';
1214
export class CopBot {
1315
private static instance: CopBot;
1416
private _bot: Bot<Context>;
@@ -79,6 +81,7 @@ export class CopBot {
7981
});
8082
} else {
8183
try {
84+
await this._bot.api.deleteWebhook();
8285
await this._bot.api.getUpdates({ offset: -1 });
8386
await this._bot.start({
8487
onStart: (botInfo) => {
@@ -94,6 +97,7 @@ export class CopBot {
9497
@Catch()
9598
async initial(): Promise<void> {
9699
new GenerateCommand(this._bot).generate();
100+
this._bot.on('my_chat_member', (ctx) => this.handleJoinNewChat(ctx));
97101
this._bot.on('message', (ctx) => this.handleMessage(ctx));
98102
await this.start();
99103
this._bot.catch((err) => {
@@ -103,9 +107,18 @@ export class CopBot {
103107
}
104108
@SaveUserData()
105109
@MessageValidator()
110+
@RateLimit({ commandLimit: 3, timeFrame: 15000 })
106111
@Catch()
107112
async handleMessage(ctx: Context) {
108113
const messageText = ctx.message?.text?.toLowerCase().trim();
114+
const msg = ctx.message?.text!;
115+
const reply = new BotReply(ctx);
116+
const user = ctx.message?.reply_to_message!.from;
117+
if (msg && msg.toLowerCase() === 'ask' && user) {
118+
const name = user.username ? `@${user.username}` : user.first_name;
119+
const responseMessage = `Dear ${name}, ask your question correctly.\nIf you want to know how to do this, read the article below:\ndontasktoask.ir`;
120+
await reply.textReply(responseMessage);
121+
}
109122
const command = messageText?.split(' ')[0]?.replace('/', '');
110123
if (command) {
111124
const handler = (GeneralCommands as any)[command] || (UserCommands as any)[command] || (AdminCommands as any)[command];
@@ -114,4 +127,22 @@ export class CopBot {
114127
}
115128
}
116129
}
130+
131+
@SaveUserData()
132+
async handleJoinNewChat(ctx: Context) {
133+
const chat = ctx.chat!;
134+
if (!chat) {
135+
return;
136+
}
137+
138+
const reply = new BotReply(ctx);
139+
const from = ctx.from;
140+
console.log(`Bot added to group ${chat.title} by ${from?.username}`);
141+
const message = `
142+
Hello ${ctx.chat?.title}!
143+
First of all, thanks to @${from?.username!} for inviting me to this awesome group!
144+
I'm here to help out and make sure everyone has a good time. Are you curious about what I can do? Just type the /help command.
145+
`;
146+
await reply.textReply(message);
147+
}
117148
}

0 commit comments

Comments
 (0)