# <============================================== IMPORTS =========================================================> import html import re from telegram import ChatPermissions, Update from telegram.error import BadRequest from telegram.ext import ( CallbackQueryHandler, CommandHandler, ContextTypes, MessageHandler, filters, ) from telegram.helpers import mention_html from Database.sql import antiflood_sql as sql from Database.sql.approve_sql import is_approved from Mikobot import dispatcher, function from Mikobot.plugins.connection import connected from Mikobot.plugins.helper_funcs.alternate import send_message from Mikobot.plugins.helper_funcs.chat_status import check_admin, is_user_admin from Mikobot.plugins.helper_funcs.string_handling import extract_time from Mikobot.plugins.log_channel import loggable # <=======================================================================================================> FLOOD_GROUP = 3 # <================================================ FUNCTION =======================================================> @loggable async def check_flood(update: Update, context: ContextTypes.DEFAULT_TYPE): user = update.effective_user chat = update.effective_chat msg = update.effective_message if not user: return "" if await is_user_admin(chat, user.id): sql.update_flood(chat.id, None) return "" if is_approved(chat.id, user.id): sql.update_flood(chat.id, None) return should_ban = sql.update_flood(chat.id, user.id) if not should_ban: return "" try: getmode, getvalue = sql.get_flood_setting(chat.id) if getmode == 1: await chat.ban_member(user.id) execstrings = "BANNED" tag = "BANNED" elif getmode == 2: await chat.ban_member(user.id) await chat.unban_member(user.id) execstrings = "KICKED" tag = "KICKED" elif getmode == 3: await context.bot.restrict_chat_member( chat.id, user.id, permissions=ChatPermissions(can_send_messages=False), ) execstrings = "MUTED" tag = "MUTED" elif getmode == 4: bantime = await extract_time(msg, getvalue) await chat.ban_member(user.id, until_date=bantime) execstrings = "BANNED for {}".format(getvalue) tag = "TBAN" elif getmode == 5: mutetime = await extract_time(msg, getvalue) await context.bot.restrict_chat_member( chat.id, user.id, until_date=mutetime, permissions=ChatPermissions(can_send_messages=False), ) execstrings = "MUTED for {}".format(getvalue) tag = "TMUTE" await send_message( update.effective_message, "Beep boop! Boop beep!\n{}!".format(execstrings), ) return ( "{}:" "\n#{}" "\nuser: {}" "\nFlooded the group.".format( tag, html.escape(chat.title), mention_html(user.id, html.escape(user.first_name)), ) ) except BadRequest: await msg.reply_text( "I can't restrict people here, give me permissions first! Until then, I'll disable anti-flood.", ) sql.set_flood(chat.id, 0) return ( "{}:" "\n#INFO" "\nDon't have enough permission to restrict users so automatically disabled anti-flood.".format( chat.title, ) ) @check_admin(permission="can_restrict_members", is_both=True, no_reply=True) async def flood_button(update: Update, context: ContextTypes.DEFAULT_TYPE): bot = context.bot query = update.callback_query user = update.effective_user match = re.match(r"unmute_flooder\((.+?)\)", query.data) if match: user_id = match.group(1) chat = update.effective_chat.id try: await bot.restrict_chat_member( chat, int(user_id), permissions=ChatPermissions( can_send_messages=True, can_send_media_messages=True, can_send_other_messages=True, can_add_web_page_previews=True, ), ) await update.effective_message.edit_text( f"Unmuted by {mention_html(user.id, html.escape(user.first_name))}.", parse_mode="HTML", ) except: pass @loggable @check_admin(is_user=True) async def set_flood(update: Update, context: ContextTypes.DEFAULT_TYPE): chat = update.effective_chat user = update.effective_user message = update.effective_message args = context.args conn = await connected(context.bot, update, chat, user.id, need_admin=True) if conn: chat_id = conn chat_obj = await dispatcher.bot.getChat(conn) chat_name = chat_obj.title else: if update.effective_message.chat.type == "private": await send_message( update.effective_message, "This command is meant to use in a group, not in PM.", ) return "" chat_id = update.effective_chat.id chat_name = update.effective_message.chat.title if len(args) >= 1: val = args[0].lower() if val in ["off", "no", "0"]: sql.set_flood(chat_id, 0) if conn: text = await message.reply_text( "Antiflood has been disabled in {}.".format(chat_name), ) else: text = await message.reply_text("Antiflood has been disabled.") elif val.isdigit(): amount = int(val) if amount <= 0: sql.set_flood(chat_id, 0) if conn: text = await message.reply_text( "Antiflood has been disabled in {}.".format(chat_name), ) else: text = await message.reply_text("Antiflood has been disabled.") return ( "{}:" "\n#SETFLOOD" "\nAdmin: {}" "\nDisable Antiflood.".format( html.escape(chat_name), mention_html(user.id, html.escape(user.first_name)), ) ) elif amount <= 3: await send_message( update.effective_message, "Antiflood must be either 0 (disabled) or a number greater than 3!", ) return "" else: sql.set_flood(chat_id, amount) if conn: text = await message.reply_text( "Antiflood limit has been set to {} in chat: {}".format( amount, chat_name, ), ) else: text = await message.reply_text( "Successfully updated antiflood limit to {}!".format(amount), ) return ( "{}:" "\n#SETFLOOD" "\nAdmin: {}" "\nSet Antiflood to {}.".format( html.escape(chat_name), mention_html(user.id, html.escape(user.first_name)), amount, ) ) else: await message.reply_text( "Invalid argument, please use a number, 'off', or 'no'." ) else: await message.reply_text( ( "Use `/setflood number` to enable antiflood.\n" "Or use `/setflood off` to disable antiflood." ), parse_mode="markdown", ) return "" async def flood(update: Update, context: ContextTypes.DEFAULT_TYPE): chat = update.effective_chat user = update.effective_user msg = update.effective_message conn = await connected(context.bot, update, chat, user.id, need_admin=False) if conn: chat_id = conn chat_obj = await dispatcher.bot.getChat(conn) chat_name = chat_obj.title else: if update.effective_message.chat.type == "private": await send_message( update.effective_message, "This command is meant to use in a group, not in PM.", ) return chat_id = update.effective_chat.id chat_name = update.effective_message.chat.title limit = sql.get_flood_limit(chat_id) if limit == 0: if conn: text = await msg.reply_text( "I'm not enforcing any flood control in {}!".format(chat_name), ) else: text = await msg.reply_text("I'm not enforcing any flood control here!") else: if conn: text = await msg.reply_text( "I'm currently restricting members after {} consecutive messages in {}.".format( limit, chat_name, ), ) else: text = await msg.reply_text( "I'm currently restricting members after {} consecutive messages.".format( limit, ), ) @check_admin(is_user=True) async def set_flood_mode(update: Update, context: ContextTypes.DEFAULT_TYPE): chat = update.effective_chat user = update.effective_user msg = update.effective_message args = context.args conn = await connected(context.bot, update, chat, user.id, need_admin=True) if conn: chat = await dispatcher.bot.getChat(conn) chat_id = conn chat_obj = await dispatcher.bot.getChat(conn) chat_name = chat_obj.title else: if update.effective_message.chat.type == "private": await send_message( update.effective_message, "This command is meant to use in a group, not in PM.", ) return "" chat = update.effective_chat chat_id = update.effective_chat.id chat_name = update.effective_message.chat.title if args: if args[0].lower() == "ban": settypeflood = "ban" sql.set_flood_strength(chat_id, 1, "0") elif args[0].lower() == "kick": settypeflood = "kick" sql.set_flood_strength(chat_id, 2, "0") elif args[0].lower() == "mute": settypeflood = "mute" sql.set_flood_strength(chat_id, 3, "0") elif args[0].lower() == "tban": if len(args) == 1: teks = """It looks like you tried to set time value for antiflood but you didn't specified time; Try, `/setfloodmode tban `. Examples of time value: 4m = 4 minutes, 3h = 3 hours, 6d = 6 days, 5w = 5 weeks.""" await send_message( update.effective_message, teks, parse_mode="markdown" ) return settypeflood = "tban for {}".format(args[1]) sql.set_flood_strength(chat_id, 4, str(args[1])) elif args[0].lower() == "tmute": if len(args) == 1: teks = """It looks like you tried to set time value for antiflood but you didn't specified time; Try, `/setfloodmode tmute `. Examples of time value: 4m = 4 minutes, 3h = 3 hours, 6d = 6 days, 5w = 5 weeks.""" await send_message( update.effective_message, teks, parse_mode="markdown" ) return settypeflood = "tmute for {}".format(args[1]) sql.set_flood_strength(chat_id, 5, str(args[1])) else: await send_message( update.effective_message, "I only understand ban/kick/mute/tban/tmute!", ) return if conn: text = await msg.reply_text( "Exceeding consecutive flood limit will result in {} in {}!".format( settypeflood, chat_name, ), ) else: text = await msg.reply_text( "Exceeding consecutive flood limit will result in {}!".format( settypeflood, ), ) return ( "{}:\n" "Admin: {}\n" "Has changed antiflood mode. User will {}.".format( settypeflood, html.escape(chat.title), mention_html(user.id, html.escape(user.first_name)), ) ) else: getmode, getvalue = sql.get_flood_setting(chat.id) if getmode == 1: settypeflood = "ban" elif getmode == 2: settypeflood = "kick" elif getmode == 3: settypeflood = "mute" elif getmode == 4: settypeflood = "tban for {}".format(getvalue) elif getmode == 5: settypeflood = "tmute for {}".format(getvalue) if conn: text = await msg.reply_text( "Sending more messages than flood limit will result in {} in {}.".format( settypeflood, chat_name, ), ) else: text = await msg.reply_text( "Sending more messages than flood limit will result in {}.".format( settypeflood, ), ) return "" def __migrate__(old_chat_id, new_chat_id): sql.migrate_chat(old_chat_id, new_chat_id) def __chat_settings__(chat_id, user_id): limit = sql.get_flood_limit(chat_id) if limit == 0: return "Not enforcing flood control." else: return "Antiflood has been set to `{}`.".format(limit) # <=================================================== HELP ====================================================> __help__ = """ ➠ *Antiflood allows you to take action on users that send more than x messages in a row. Exceeding the set flood will result in restricting that user.* ➠ *Admin Only* » /flood: Get the current antiflood settings. » /setflood : Set the number of messages after which to take action on a user. Set to '0', 'off', or 'no' to disable. » /setfloodmode : Choose which action to take on a user who has been flooding. Options: ban/kick/mute/tban/tmute. """ __mod_name__ = "ANTI-FLOOD" # <================================================ HANDLER =======================================================> FLOOD_BAN_HANDLER = MessageHandler( filters.ALL & ~filters.StatusUpdate.ALL & filters.ChatType.GROUPS, check_flood, block=False, ) SET_FLOOD_HANDLER = CommandHandler( "setflood", set_flood, filters=filters.ChatType.GROUPS, block=False ) SET_FLOOD_MODE_HANDLER = CommandHandler( "setfloodmode", set_flood_mode, block=False ) # , filters=filters.ChatType.GROUPS) FLOOD_QUERY_HANDLER = CallbackQueryHandler( flood_button, pattern=r"unmute_flooder", block=False ) FLOOD_HANDLER = CommandHandler( "flood", flood, filters=filters.ChatType.GROUPS, block=False ) function(FLOOD_BAN_HANDLER, FLOOD_GROUP) function(FLOOD_QUERY_HANDLER) function(SET_FLOOD_HANDLER) function(SET_FLOOD_MODE_HANDLER) function(FLOOD_HANDLER) __handlers__ = [ (FLOOD_BAN_HANDLER, FLOOD_GROUP), SET_FLOOD_HANDLER, FLOOD_HANDLER, SET_FLOOD_MODE_HANDLER, ] # <================================================ END =======================================================>