Merge pull request #37 from Infamous-Hydra/Infamous-Hydra-patch-9
Browse files- 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 =======================================================>
|