diff --git a/app/__init__.py b/app/__init__.py index a37cf65..3215a30 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -14,5 +14,3 @@ if "com.termux" not in os.environ.get("PATH", ""): uvloop.install() bot = BOT() - -from app.core.client.conversation import Conversation as Convo # NOQA diff --git a/app/config.py b/app/config.py index 753c28d..c2e9112 100644 --- a/app/config.py +++ b/app/config.py @@ -15,6 +15,10 @@ class Config: DB_URL: str = os.environ.get("DB_URL") + FBAN_LOG_CHANNEL: int = int( + os.environ.get("FBAN_LOG_CHANNEL", os.environ.get("LOG_CHAT")) + ) + LOG_CHAT: int = int(os.environ.get("LOG_CHAT")) TRIGGER: str = os.environ.get("TRIGGER", ".") diff --git a/app/core/__init__.py b/app/core/__init__.py index 6ef3717..f314825 100644 --- a/app/core/__init__.py +++ b/app/core/__init__.py @@ -1,3 +1,5 @@ from app.core.client import filters from app.core.types.callback_query import CallbackQuery -from app.core.types.message import Message + +from app.core.client.conversation import Conversation # NOQA +from app.core.types.message import Message # NOQA diff --git a/app/core/client/client.py b/app/core/client/client.py index e40d18a..2f4980d 100644 --- a/app/core/client/client.py +++ b/app/core/client/client.py @@ -5,12 +5,12 @@ import sys from functools import wraps from io import BytesIO -from pyrogram import Client, idle +from pyrogram import Client, filters, idle from pyrogram.enums import ParseMode from pyrogram.types import Message as Msg from app import DB, Config -from app.core import Message +from app.core import Conversation, Message from app.utils import aiohttp_tools @@ -38,13 +38,11 @@ class BOT(Client): ) @staticmethod - def add_cmd(cmd: str, cb: bool = False): + def add_cmd(cmd: str): def the_decorator(func): @wraps(func) def wrapper(): config_dict = Config.CMD_DICT - if cb: - config_dict = Config.CALLBACK_DICT if isinstance(cmd, list): for _cmd in cmd: config_dict[_cmd] = func @@ -56,6 +54,19 @@ class BOT(Client): return the_decorator + @staticmethod + async def get_response( + chat_id: int, filters: filters.Filter = None, timeout: int = 8 + ) -> Message | None: + try: + async with Conversation( + chat_id=chat_id, filters=filters, timeout=timeout + ) as convo: + response: Message | None = await convo.get_response() + return response + except Conversation.TimeOutError: + return + async def boot(self) -> None: await super().start() await import_modules() @@ -90,7 +101,7 @@ class BOT(Client): parse_mode=ParseMode.HTML, ) -> Message | Msg: if message: - return (await message.copy(chat_id=Config.LOG_CHAT)) + return await message.copy(chat_id=Config.LOG_CHAT) if traceback: text = f""" #Traceback diff --git a/app/core/client/conversation.py b/app/core/client/conversation.py index bb96a66..4c381f9 100644 --- a/app/core/client/conversation.py +++ b/app/core/client/conversation.py @@ -4,7 +4,7 @@ import json from pyrogram.filters import Filter from pyrogram.types import Message -from app import Config, bot +from app import Config class Conversation: @@ -20,7 +20,6 @@ class Conversation: super().__init__("Conversation Timeout") def __init__(self, chat_id: int, filters: Filter | None = None, timeout: int = 10): - self._client = bot self.chat_id = chat_id self.filters = filters self.timeout = timeout diff --git a/app/core/types/message.py b/app/core/types/message.py index 1956118..5f7c07b 100644 --- a/app/core/types/message.py +++ b/app/core/types/message.py @@ -2,10 +2,12 @@ import asyncio from functools import cached_property from pyrogram.errors import MessageDeleteForbidden +from pyrogram.filters import Filter from pyrogram.types import Message as Msg from pyrogram.types import User from app import Config +from app.core import Conversation class Message(Msg): @@ -112,6 +114,16 @@ class Message(Msg): except Exception as e: return [e, reason] + async def get_response(self, filters: Filter = None, timeout: int = 8): + try: + async with Conversation( + chat_id=self.chat.id, filters=filters, timeout=timeout + ) as convo: + response: Message | None = await convo.get_response() + return response + except Conversation.TimeOutError: + return + async def reply( self, text, del_in: int = 0, block: bool = True, **kwargs ) -> "Message": diff --git a/app/plugins/fbans.py b/app/plugins/fbans.py new file mode 100644 index 0000000..b87e6ff --- /dev/null +++ b/app/plugins/fbans.py @@ -0,0 +1,109 @@ +import asyncio +from functools import cached_property + +from motor.core import AgnosticCollection +from pyrogram import filters +from pyrogram.types import Chat, User + +from app import DB, Config, bot +from app.core import Message +from app.utils.db_utils import add_data, delete_data + +FEDS: AgnosticCollection = DB.FED_LIST +FILTERS: filters.Filter = filters.user([609517172, 2059887769]) +FBAN_REGEX: filters.Filter = filters.regex( + r"(New FedBan|starting a federation ban|Starting a federation ban|start a federation ban|FedBan Reason update|FedBan reason updated|Would you like to update this reason)" +) + + +class _User(User): + def __init__(self, id): + super().__init__(id=id) + + @cached_property + def mention(self) -> str: + return f"{self.id}" + + +@bot.add_cmd(cmd="addf") +async def add_fed(bot: bot, message: Message): + data = dict( + name=message.flt_input or message.chat.title, type=str(message.chat.type) + ) + await add_data(collection=FEDS, id=message.chat.id, data=data) + await message.reply(f"{data['name']} added to FED LIST.", del_in=5, block=False) + await bot.log(text=f"#FBANS\n{data['name']} {message.chat.id} added to FED LIST.") + + +@bot.add_cmd(cmd="delf") +async def remove_fed(bot: bot, message: Message): + if "-all" in message.flags: + await FEDS.drop() + await message.reply("FED LIST cleared.") + return + chat: int | str | Chat = message.flt_input or message.chat + name = "" + if isinstance(chat, Chat): + name = f"Chat: {chat.title}\n" + chat = chat.id + elif chat.isdigit(): + chat = int(chat) + deleted: bool | None = await delete_data(collection=FEDS, id=chat) + if deleted: + await message.reply( + f"{name}{chat} removed from FED LIST.", del_in=8, block=False + ) + await bot.log(text=f"#FBANS\n{name}{chat} removed from FED LIST.") + else: + await message.reply(f"{name or chat} not in FED LIST.", del_in=8) + + +@bot.add_cmd(cmd="fban") +async def fed_ban(bot: bot, message: Message): + await message.delete() + progress: Message = await message.reply("❯") + user, reason = await message.extract_user_n_reason() + if isinstance(user, str): + await progress.edit(user) + return + if not isinstance(user, User): + user = _User(id=message.text_list[1]) + if user.id in Config.USERS: + await progress.edit("Cannot Fban Owner/Sudo users.") + return + await progress.edit("❯❯") + total: int = 0 + failed: list[str] = [] + async for fed in FEDS.find(): + chat_id = int(fed["_id"]) + total += 1 + cmd: Message = await bot.send_message( + chat_id=chat_id, + text=f"!fban {user.mention} {reason}", + disable_web_page_preview=True, + ) + response: Message | None = await cmd.get_response( + filters=(FILTERS), timeout=8 + ) + if not response or not (await FBAN_REGEX(bot, response)): + failed.append(fed["name"]) + elif "Would you like to update this reason" in response.text: + await response.click("Update reason") + await asyncio.sleep(0.8) + if not total: + await progress.edit("You Don't have any feds connected!") + return + resp_str = f"❯❯❯ FBanned {user.mention}\nID: {user.id}\nReason: {reason}\n" + if failed: + resp_str += f"Failed in: {len(failed)}/{total}\n• " + "\n• ".join(failed) + else: + resp_str += f"Success! Fbanned in {total} feds." + await progress.edit( + text=resp_str, del_in=8, block=False, disable_web_page_preview=True + ) + await bot.send_message(chat_id=Config.FBAN_LOG_CHANNEL, text=resp_str) + + +@bot.add_cmd(cmd="unfban") +async def un_fban(bot: bot, message: Message): + ... diff --git a/sample-config.env b/sample-config.env index a346021..090e8e0 100644 --- a/sample-config.env +++ b/sample-config.env @@ -8,6 +8,9 @@ DEV_MODE=0 DB_URL= # Mongo DB cluster URL +FBAN_LOG_CHANNEL= +# FedBan Proof and logs. + LOG_CHAT= # Bot logs chat @@ -16,4 +19,4 @@ SESSION_STRING="" USERS = [1223478] # Separate multiple values with , -UPSTREAM_REPO = "https://github.com/thedragonsinn/plain-ub" \ No newline at end of file +UPSTREAM_REPO = "https://github.com/thedragonsinn/plain-ub"