Karma commited on
Commit
d9b6ce1
·
2 Parent(s): 0b2a013 71be339

Merge pull request #37 from Infamous-Hydra/Infamous-Hydra-patch-9

Browse files
Files changed (1) hide show
  1. Mikobot/plugins/warns.py +576 -0
Mikobot/plugins/warns.py ADDED
@@ -0,0 +1,576 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # <============================================== IMPORTS =========================================================>
2
+ import html
3
+ import re
4
+ from typing import Optional
5
+
6
+ from telegram import (
7
+ CallbackQuery,
8
+ Chat,
9
+ ChatMemberAdministrator,
10
+ ChatMemberOwner,
11
+ InlineKeyboardButton,
12
+ InlineKeyboardMarkup,
13
+ Message,
14
+ Update,
15
+ User,
16
+ )
17
+ from telegram.constants import MessageLimit, ParseMode
18
+ from telegram.error import BadRequest
19
+ from telegram.ext import (
20
+ ApplicationHandlerStop,
21
+ CallbackQueryHandler,
22
+ CommandHandler,
23
+ ContextTypes,
24
+ MessageHandler,
25
+ filters,
26
+ )
27
+ from telegram.helpers import mention_html
28
+
29
+ from Database.sql import warns_sql as sql
30
+ from Database.sql.approve_sql import is_approved
31
+ from Mikobot import dispatcher, function
32
+ from Mikobot.utils.can_restrict import BAN_STICKER
33
+ from Mikobot.plugins.disable import DisableAbleCommandHandler
34
+ from Mikobot.plugins.helper_funcs.chat_status import check_admin, is_user_admin
35
+ from Mikobot.plugins.helper_funcs.extraction import (
36
+ extract_text,
37
+ extract_user,
38
+ extract_user_and_text,
39
+ )
40
+ from Mikobot.plugins.helper_funcs.misc import split_message
41
+ from Mikobot.plugins.helper_funcs.string_handling import split_quotes
42
+ from Mikobot.plugins.log_channel import loggable
43
+
44
+ # <=======================================================================================================>
45
+
46
+ WARN_HANDLER_GROUP = 9
47
+ CURRENT_WARNING_FILTER_STRING = "<b>Current warning filters in this chat:</b>\n"
48
+
49
+
50
+ # <================================================ FUNCTION =======================================================>
51
+ # Not async
52
+ async def warn(
53
+ user: User,
54
+ chat: Chat,
55
+ reason: str,
56
+ message: Message,
57
+ warner: User = None,
58
+ ) -> str:
59
+ if await is_user_admin(chat, user.id):
60
+ await message.reply_text("Damn admins, They are too far to be Warned")
61
+ return
62
+
63
+ if warner:
64
+ warner_tag = mention_html(warner.id, warner.first_name)
65
+ else:
66
+ warner_tag = "Automated warn filter."
67
+
68
+ limit, soft_warn = sql.get_warn_setting(chat.id)
69
+ num_warns, reasons = sql.warn_user(user.id, chat.id, reason)
70
+ if num_warns >= limit:
71
+ sql.reset_warns(user.id, chat.id)
72
+ if soft_warn: # punch
73
+ chat.unban_member(user.id)
74
+ reply = (
75
+ f"<code>❕</code><b>Kick Event</b>\n"
76
+ f"<code> </code><b>• User:</b> {mention_html(user.id, user.first_name)}\n"
77
+ f"<code> </code><b>• Count:</b> {limit}"
78
+ )
79
+
80
+ else: # ban
81
+ await chat.ban_member(user.id)
82
+ reply = (
83
+ f"<code>❕</code><b>Ban Event</b>\n"
84
+ f"<code> </code><b>• User:</b> {mention_html(user.id, user.first_name)}\n"
85
+ f"<code> </code><b>• Count:</b> {limit}"
86
+ )
87
+
88
+ for warn_reason in reasons:
89
+ reply += f"\n - {html.escape(warn_reason)}"
90
+
91
+ await message.reply_sticker(BAN_STICKER) # Saitama's sticker
92
+ keyboard = None
93
+ log_reason = (
94
+ f"<b>{html.escape(chat.title)}:</b>\n"
95
+ f"#WARN_BAN\n"
96
+ f"<b>Admin:</b> {warner_tag}\n"
97
+ f"<b>User:</b> {mention_html(user.id, user.first_name)}\n"
98
+ f"<b>Reason:</b> {reason}\n"
99
+ f"<b>Counts:</b> <code>{num_warns}/{limit}</code>"
100
+ )
101
+
102
+ else:
103
+ keyboard = InlineKeyboardMarkup(
104
+ [
105
+ [
106
+ InlineKeyboardButton(
107
+ "🔘 Remove warn",
108
+ callback_data="rm_warn({})".format(user.id),
109
+ ),
110
+ ],
111
+ ],
112
+ )
113
+
114
+ reply = (
115
+ f"<code>❕</code><b>Warn Event</b>\n"
116
+ f"<code> </code><b>• User:</b> {mention_html(user.id, user.first_name)}\n"
117
+ f"<code> </code><b>• Count:</b> {num_warns}/{limit}"
118
+ )
119
+ if reason:
120
+ reply += f"\n<code> </code><b>• Reason:</b> {html.escape(reason)}"
121
+
122
+ log_reason = (
123
+ f"<b>{html.escape(chat.title)}:</b>\n"
124
+ f"#WARN\n"
125
+ f"<b>Admin:</b> {warner_tag}\n"
126
+ f"<b>User:</b> {mention_html(user.id, user.first_name)}\n"
127
+ f"<b>Reason:</b> {reason}\n"
128
+ f"<b>Counts:</b> <code>{num_warns}/{limit}</code>"
129
+ )
130
+
131
+ try:
132
+ await message.reply_text(
133
+ reply, reply_markup=keyboard, parse_mode=ParseMode.HTML
134
+ )
135
+ except BadRequest as excp:
136
+ if excp.message == "Reply message not found":
137
+ # Do not reply
138
+ await message.reply_text(
139
+ reply,
140
+ reply_markup=keyboard,
141
+ parse_mode=ParseMode.HTML,
142
+ quote=False,
143
+ )
144
+ else:
145
+ raise
146
+ return log_reason
147
+
148
+
149
+ @loggable
150
+ async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
151
+ query: Optional[CallbackQuery] = update.callback_query
152
+ user: Optional[User] = update.effective_user
153
+ match = re.match(r"rm_warn\((.+?)\)", query.data)
154
+ if match:
155
+ user_id = match.group(1)
156
+ chat: Optional[Chat] = update.effective_chat
157
+ chat_member = await chat.get_member(user.id)
158
+ if isinstance(chat_member, (ChatMemberAdministrator, ChatMemberOwner)):
159
+ pass
160
+ else:
161
+ await query.answer("You need to be admin to do this!")
162
+ return
163
+ res = sql.remove_warn(user_id, chat.id)
164
+ if res:
165
+ await update.effective_message.edit_text(
166
+ "Warn removed by {}.".format(mention_html(user.id, user.first_name)),
167
+ parse_mode=ParseMode.HTML,
168
+ )
169
+ user_member = await chat.get_member(user_id)
170
+ return (
171
+ f"<b>{html.escape(chat.title)}:</b>\n"
172
+ f"#UNWARN\n"
173
+ f"<b>Admin:</b> {mention_html(user.id, user.first_name)}\n"
174
+ f"<b>User:</b> {mention_html(user_member.user.id, user_member.user.first_name)}"
175
+ )
176
+ else:
177
+ await update.effective_message.edit_text(
178
+ "User already has no warns.",
179
+ parse_mode=ParseMode.HTML,
180
+ )
181
+
182
+ return ""
183
+
184
+
185
+ @loggable
186
+ @check_admin(permission="can_restrict_members", is_both=True)
187
+ async def warn_user(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
188
+ args = context.args
189
+ message: Optional[Message] = update.effective_message
190
+ chat: Optional[Chat] = update.effective_chat
191
+ warner: Optional[User] = update.effective_user
192
+
193
+ user_id, reason = await extract_user_and_text(message, context, args)
194
+ if (
195
+ message.text.startswith("/d")
196
+ and message.reply_to_message
197
+ and not message.reply_to_message.forum_topic_created
198
+ ):
199
+ await message.reply_to_message.delete()
200
+ if user_id:
201
+ if (
202
+ message.reply_to_message
203
+ and message.reply_to_message.from_user.id == user_id
204
+ ):
205
+ return await warn(
206
+ message.reply_to_message.from_user,
207
+ chat,
208
+ reason,
209
+ message.reply_to_message,
210
+ warner,
211
+ )
212
+ else:
213
+ member = await chat.get_member(user_id)
214
+ return await warn(member.user, chat, reason, message, warner)
215
+ else:
216
+ await message.reply_text("That looks like an invalid User ID to me.")
217
+ return ""
218
+
219
+
220
+ @loggable
221
+ @check_admin(is_both=True)
222
+ async def reset_warns(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
223
+ args = context.args
224
+ message: Optional[Message] = update.effective_message
225
+ chat: Optional[Chat] = update.effective_chat
226
+ user: Optional[User] = update.effective_user
227
+
228
+ user_id = await extract_user(message, context, args)
229
+
230
+ if user_id:
231
+ sql.reset_warns(user_id, chat.id)
232
+ await message.reply_text("Warns have been reset!")
233
+ warned = await chat.get_member(user_id).user
234
+ return (
235
+ f"<b>{html.escape(chat.title)}:</b>\n"
236
+ f"#RESETWARNS\n"
237
+ f"<b>Admin:</b> {mention_html(user.id, user.first_name)}\n"
238
+ f"<b>User:</b> {mention_html(warned.id, warned.first_name)}"
239
+ )
240
+ else:
241
+ await message.reply_text("No user has been designated!")
242
+ return ""
243
+
244
+
245
+ async def warns(update: Update, context: ContextTypes.DEFAULT_TYPE):
246
+ args = context.args
247
+ message: Optional[Message] = update.effective_message
248
+ chat: Optional[Chat] = update.effective_chat
249
+ user_id = await extract_user(message, context, args) or update.effective_user.id
250
+ result = sql.get_warns(user_id, chat.id)
251
+
252
+ if result and result[0] != 0:
253
+ num_warns, reasons = result
254
+ limit, soft_warn = sql.get_warn_setting(chat.id)
255
+
256
+ if reasons:
257
+ text = (
258
+ f"This user has {num_warns}/{limit} warns, for the following reasons:"
259
+ )
260
+ for reason in reasons:
261
+ text += f"\n • {reason}"
262
+
263
+ msgs = split_message(text)
264
+ for msg in msgs:
265
+ await update.effective_message.reply_text(msg)
266
+ else:
267
+ await update.effective_message.reply_text(
268
+ f"User has {num_warns}/{limit} warns, but no reasons for any of them.",
269
+ )
270
+ else:
271
+ await update.effective_message.reply_text("This user doesn't have any warns!")
272
+
273
+
274
+ # Dispatcher handler stop - do not async
275
+ @check_admin(is_user=True)
276
+ async def add_warn_filter(update: Update, context: ContextTypes.DEFAULT_TYPE):
277
+ chat: Optional[Chat] = update.effective_chat
278
+ msg: Optional[Message] = update.effective_message
279
+
280
+ args = msg.text.split(
281
+ None,
282
+ 1,
283
+ ) # use python's maxsplit to separate Cmd, keyword, and reply_text
284
+
285
+ if len(args) < 2:
286
+ return
287
+
288
+ extracted = split_quotes(args[1])
289
+
290
+ if len(extracted) >= 2:
291
+ # set trigger -> lower, so as to avoid adding duplicate filters with different cases
292
+ keyword = extracted[0].lower()
293
+ content = extracted[1]
294
+
295
+ else:
296
+ return
297
+
298
+ # Note: perhaps handlers can be removed somehow using sql.get_chat_filters
299
+ for handler in dispatcher.handlers.get(WARN_HANDLER_GROUP, []):
300
+ if handler.filters == (keyword, chat.id):
301
+ dispatcher.remove_handler(handler, WARN_HANDLER_GROUP)
302
+
303
+ sql.add_warn_filter(chat.id, keyword, content)
304
+
305
+ await update.effective_message.reply_text(f"Warn handler added for '{keyword}'!")
306
+ raise ApplicationHandlerStop
307
+
308
+
309
+ @check_admin(is_user=True)
310
+ async def remove_warn_filter(update: Update, context: ContextTypes.DEFAULT_TYPE):
311
+ chat: Optional[Chat] = update.effective_chat
312
+ msg: Optional[Message] = update.effective_message
313
+
314
+ args = msg.text.split(
315
+ None,
316
+ 1,
317
+ ) # use python's maxsplit to separate Cmd, keyword, and reply_text
318
+
319
+ if len(args) < 2:
320
+ return
321
+
322
+ extracted = split_quotes(args[1])
323
+
324
+ if len(extracted) < 1:
325
+ return
326
+
327
+ to_remove = extracted[0]
328
+
329
+ chat_filters = sql.get_chat_warn_triggers(chat.id)
330
+
331
+ if not chat_filters:
332
+ await msg.reply_text("No warning filters are active here!")
333
+ return
334
+
335
+ for filt in chat_filters:
336
+ if filt == to_remove:
337
+ sql.remove_warn_filter(chat.id, to_remove)
338
+ await msg.reply_text("Okay, I'll stop warning people for that.")
339
+ raise ApplicationHandlerStop
340
+
341
+ await msg.reply_text(
342
+ "That's not a current warning filter - run /warnlist for all active warning filters.",
343
+ )
344
+
345
+
346
+ async def list_warn_filters(update: Update, context: ContextTypes.DEFAULT_TYPE):
347
+ chat: Optional[Chat] = update.effective_chat
348
+ all_handlers = sql.get_chat_warn_triggers(chat.id)
349
+
350
+ if not all_handlers:
351
+ await update.effective_message.reply_text("No warning filters are active here!")
352
+ return
353
+
354
+ filter_list = CURRENT_WARNING_FILTER_STRING
355
+ for keyword in all_handlers:
356
+ entry = f" - {html.escape(keyword)}\n"
357
+ if len(entry) + len(filter_list) > MessageLimit.MAX_TEXT_LENGTH:
358
+ await update.effective_message.reply_text(
359
+ filter_list, parse_mode=ParseMode.HTML
360
+ )
361
+ filter_list = entry
362
+ else:
363
+ filter_list += entry
364
+
365
+ if filter_list != CURRENT_WARNING_FILTER_STRING:
366
+ await update.effective_message.reply_text(
367
+ filter_list, parse_mode=ParseMode.HTML
368
+ )
369
+
370
+
371
+ @loggable
372
+ async def reply_filter(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
373
+ chat: Optional[Chat] = update.effective_chat
374
+ message: Optional[Message] = update.effective_message
375
+ user: Optional[User] = update.effective_user
376
+
377
+ if not user: # Ignore channel
378
+ return
379
+
380
+ if user.id == 777000:
381
+ return
382
+ if is_approved(chat.id, user.id):
383
+ return
384
+ chat_warn_filters = sql.get_chat_warn_triggers(chat.id)
385
+ to_match = await extract_text(message)
386
+ if not to_match:
387
+ return ""
388
+
389
+ for keyword in chat_warn_filters:
390
+ pattern = r"( |^|[^\w])" + re.escape(keyword) + r"( |$|[^\w])"
391
+ if re.search(pattern, to_match, flags=re.IGNORECASE):
392
+ user: Optional[User] = update.effective_user
393
+ warn_filter = sql.get_warn_filter(chat.id, keyword)
394
+ return await warn(user, chat, warn_filter.reply, message)
395
+ return ""
396
+
397
+
398
+ @check_admin(is_user=True)
399
+ @loggable
400
+ async def set_warn_limit(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
401
+ args = context.args
402
+ chat: Optional[Chat] = update.effective_chat
403
+ user: Optional[User] = update.effective_user
404
+ msg: Optional[Message] = update.effective_message
405
+
406
+ if args:
407
+ if args[0].isdigit():
408
+ if int(args[0]) < 3:
409
+ await msg.reply_text("The minimum warn limit is 3!")
410
+ else:
411
+ sql.set_warn_limit(chat.id, int(args[0]))
412
+ await msg.reply_text("Updated the warn limit to {}".format(args[0]))
413
+ return (
414
+ f"<b>{html.escape(chat.title)}:</b>\n"
415
+ f"#SET_WARN_LIMIT\n"
416
+ f"<b>Admin:</b> {mention_html(user.id, user.first_name)}\n"
417
+ f"Set the warn limit to <code>{args[0]}</code>"
418
+ )
419
+ else:
420
+ await msg.reply_text("Give me a number as an arg!")
421
+ else:
422
+ limit, soft_warn = sql.get_warn_setting(chat.id)
423
+
424
+ await msg.reply_text("The current warn limit is {}".format(limit))
425
+ return ""
426
+
427
+
428
+ @check_admin(is_user=True)
429
+ async def set_warn_strength(update: Update, context: ContextTypes.DEFAULT_TYPE):
430
+ args = context.args
431
+ chat: Optional[Chat] = update.effective_chat
432
+ user: Optional[User] = update.effective_user
433
+ msg: Optional[Message] = update.effective_message
434
+
435
+ if args:
436
+ if args[0].lower() in ("on", "yes"):
437
+ sql.set_warn_strength(chat.id, False)
438
+ await msg.reply_text("Too many warns will now result in a Ban!")
439
+ return (
440
+ f"<b>{html.escape(chat.title)}:</b>\n"
441
+ f"<b>Admin:</b> {mention_html(user.id, user.first_name)}\n"
442
+ f"Has enabled strong warns. Users will be seriously Kicked.(banned)"
443
+ )
444
+
445
+ elif args[0].lower() in ("off", "no"):
446
+ sql.set_warn_strength(chat.id, True)
447
+ await msg.reply_text(
448
+ "Too many warns will now result in a normal Kick! Users will be able to join again after.",
449
+ )
450
+ return (
451
+ f"<b>{html.escape(chat.title)}:</b>\n"
452
+ f"<b>Admin:</b> {mention_html(user.id, user.first_name)}\n"
453
+ f"Has disabled strong Kicks. I will use normal kick on users."
454
+ )
455
+
456
+ else:
457
+ await msg.reply_text("I only understand on/yes/no/off!")
458
+ else:
459
+ limit, soft_warn = sql.get_warn_setting(chat.id)
460
+ if soft_warn:
461
+ await msg.reply_text(
462
+ "Warns are currently set to *kick* users when they exceed the limits.",
463
+ parse_mode=ParseMode.MARKDOWN,
464
+ )
465
+ else:
466
+ await msg.reply_text(
467
+ "Warns are currently set to *Ban* users when they exceed the limits.",
468
+ parse_mode=ParseMode.MARKDOWN,
469
+ )
470
+ return ""
471
+
472
+
473
+ def __stats__():
474
+ return (
475
+ f"• {sql.num_warns()} overall warns, across {sql.num_warn_chats()} chats.\n"
476
+ f"• {sql.num_warn_filters()} warn filters, across {sql.num_warn_filter_chats()} chats."
477
+ )
478
+
479
+
480
+ async def __import_data__(chat_id, data, message):
481
+ for user_id, count in data.get("warns", {}).items():
482
+ for x in range(int(count)):
483
+ sql.warn_user(user_id, chat_id)
484
+
485
+
486
+ def __migrate__(old_chat_id, new_chat_id):
487
+ sql.migrate_chat(old_chat_id, new_chat_id)
488
+
489
+
490
+ def __chat_settings__(chat_id, user_id):
491
+ num_warn_filters = sql.num_warn_chat_filters(chat_id)
492
+ limit, soft_warn = sql.get_warn_setting(chat_id)
493
+ return (
494
+ f"This chat has `{num_warn_filters}` warn filters. "
495
+ f"It takes `{limit}` warns before the user gets *{'kicked' if soft_warn else 'banned'}*."
496
+ )
497
+
498
+
499
+ # <=================================================== HELP ====================================================>
500
+
501
+
502
+ __help__ = """
503
+ » /warns <userhandle>: get a user's number, and reason, of warns.
504
+
505
+ » /warnlist: list of all current warning filters
506
+
507
+ ➠ *Admins only:*
508
+
509
+ » /warn <userhandle>: warn a user. After 3 warns, the user will be banned from the group. Can also be used as a reply.
510
+
511
+ » /dwarn <userhandle>: warn a user and delete the message. After 3 warns, the user will be banned from the group. Can also be used as a reply.
512
+
513
+ » /resetwarn <userhandle>: reset the warns for a user. Can also be used as a reply.
514
+
515
+ » /addwarn <keyword> <reply message>: set a warning filter on a certain keyword. If you want your keyword to \
516
+ be a sentence, encompass it with quotes, as such: `/addwarn "very angry" This is an angry user`.
517
+
518
+ » /nowarn <keyword>: stop a warning filter
519
+
520
+ » /warnlimit <num>: set the warning limit
521
+
522
+ » /strongwarn <on/yes/off/no>: If set to on, exceeding the warn limit will result in a ban. Else, will just kick.
523
+ """
524
+
525
+ __mod_name__ = "WARN"
526
+
527
+ # <================================================ HANDLER =======================================================>
528
+ WARN_HANDLER = CommandHandler(
529
+ ["warn", "dwarn"], warn_user, filters=filters.ChatType.GROUPS, block=False
530
+ )
531
+ RESET_WARN_HANDLER = CommandHandler(
532
+ ["resetwarn", "resetwarns"],
533
+ reset_warns,
534
+ filters=filters.ChatType.GROUPS,
535
+ block=False,
536
+ )
537
+ CALLBACK_QUERY_HANDLER = CallbackQueryHandler(button, pattern=r"rm_warn", block=False)
538
+ MYWARNS_HANDLER = DisableAbleCommandHandler(
539
+ "warns", warns, filters=filters.ChatType.GROUPS, block=False
540
+ )
541
+ ADD_WARN_HANDLER = CommandHandler(
542
+ "addwarn", add_warn_filter, filters=filters.ChatType.GROUPS
543
+ )
544
+ RM_WARN_HANDLER = CommandHandler(
545
+ ["nowarn", "stopwarn"],
546
+ remove_warn_filter,
547
+ filters=filters.ChatType.GROUPS,
548
+ )
549
+ LIST_WARN_HANDLER = DisableAbleCommandHandler(
550
+ ["warnlist", "warnfilters"],
551
+ list_warn_filters,
552
+ filters=filters.ChatType.GROUPS,
553
+ admin_ok=True,
554
+ block=False,
555
+ )
556
+ WARN_FILTER_HANDLER = MessageHandler(
557
+ filters.TEXT & filters.ChatType.GROUPS, reply_filter, block=False
558
+ )
559
+ WARN_LIMIT_HANDLER = CommandHandler(
560
+ "warnlimit", set_warn_limit, filters=filters.ChatType.GROUPS, block=False
561
+ )
562
+ WARN_STRENGTH_HANDLER = CommandHandler(
563
+ "strongwarn", set_warn_strength, filters=filters.ChatType.GROUPS, block=False
564
+ )
565
+
566
+ function(WARN_HANDLER)
567
+ function(CALLBACK_QUERY_HANDLER)
568
+ function(RESET_WARN_HANDLER)
569
+ function(MYWARNS_HANDLER)
570
+ function(ADD_WARN_HANDLER)
571
+ function(RM_WARN_HANDLER)
572
+ function(LIST_WARN_HANDLER)
573
+ function(WARN_LIMIT_HANDLER)
574
+ function(WARN_STRENGTH_HANDLER)
575
+ function(WARN_FILTER_HANDLER, WARN_HANDLER_GROUP)
576
+ # <================================================ END =======================================================>