From 96caa41d6b8e6ba0310ca96f2e46aa6bb356eafd Mon Sep 17 00:00:00 2001 From: yasirarism <55983182+yasirarism@users.noreply.github.com> Date: Tue, 4 Jul 2023 10:32:16 +0700 Subject: [PATCH] coab dulu --- misskaty/core/custom_filter.py | 8 - misskaty/core/message_utils.py | 67 -------- .../misskaty_patch/decorators/__init__.py | 3 +- .../misskaty_patch/decorators/callback.py | 100 ++++++++++++ .../core/misskaty_patch/decorators/command.py | 10 +- .../core/misskaty_patch/utils/__init__.py | 4 +- .../core/misskaty_patch/utils/admin_utils.py | 154 ++++++++++++++++++ .../core/misskaty_patch/utils/get_user.py | 122 ++++++++++++++ .../misskaty_patch/utils/handler_error.py | 12 +- misskaty/plugins/chatbot_ai.py | 2 +- misskaty/plugins/subscene_dl.py | 2 +- 11 files changed, 397 insertions(+), 87 deletions(-) delete mode 100644 misskaty/core/custom_filter.py delete mode 100644 misskaty/core/message_utils.py create mode 100644 misskaty/core/misskaty_patch/decorators/callback.py create mode 100644 misskaty/core/misskaty_patch/utils/admin_utils.py create mode 100644 misskaty/core/misskaty_patch/utils/get_user.py diff --git a/misskaty/core/custom_filter.py b/misskaty/core/custom_filter.py deleted file mode 100644 index 27887beb..00000000 --- a/misskaty/core/custom_filter.py +++ /dev/null @@ -1,8 +0,0 @@ -from pyrogram import filters - - -def pesanedit(_, __, m): - return bool(m.edit_date) - - -edited = filters.create(pesanedit) diff --git a/misskaty/core/message_utils.py b/misskaty/core/message_utils.py deleted file mode 100644 index 47f2484f..00000000 --- a/misskaty/core/message_utils.py +++ /dev/null @@ -1,67 +0,0 @@ -import asyncio -from logging import getLogger - -from pyrogram.errors import ( - ChatAdminRequired, - ChatWriteForbidden, - FloodWait, - MessageDeleteForbidden, - MessageEmpty, - MessageIdInvalid, - MessageNotModified, -) - -LOGGER = getLogger(__name__) - -# handler for TG function, so need write exception in every code - - -# Send MSG Pyro -async def kirimPesan(msg, text, **kwargs): - try: - return await msg.reply(text, **kwargs) - except FloodWait as e: - LOGGER.warning(str(e)) - await asyncio.sleep(e.value) - return await kirimPesan(msg, text, **kwargs) - except (ChatWriteForbidden, ChatAdminRequired): - LOGGER.info( - f"Leaving from {msg.chat.title} [{msg.chat.id}] because doesn't have admin permission." - ) - return await msg.chat.leave() - except Exception as e: - LOGGER.error(str(e)) - return - - -# Edit MSG Pyro -async def editPesan(msg, text, **kwargs): - try: - return await msg.edit(text, **kwargs) - except FloodWait as e: - LOGGER.warning(str(e)) - await asyncio.sleep(e.value) - return await editPesan(msg, text, **kwargs) - except (MessageNotModified, MessageIdInvalid, MessageEmpty): - return - except (ChatWriteForbidden, ChatAdminRequired): - LOGGER.info( - f"Leaving from {msg.chat.title} [{msg.chat.id}] because doesn't have admin permission." - ) - return await msg.chat.leave() - except Exception as e: - LOGGER.error(str(e)) - return - - -async def hapusPesan(msg): - try: - return await msg.delete() - except (MessageDeleteForbidden, ChatAdminRequired): - return - except FloodWait as e: - LOGGER.warning(str(e)) - await asyncio.sleep(e.value) - return await hapusPesan(msg) - except Exception as e: - LOGGER.error(str(e)) diff --git a/misskaty/core/misskaty_patch/decorators/__init__.py b/misskaty/core/misskaty_patch/decorators/__init__.py index 5e53d88f..b52193fd 100644 --- a/misskaty/core/misskaty_patch/decorators/__init__.py +++ b/misskaty/core/misskaty_patch/decorators/__init__.py @@ -1 +1,2 @@ -from .command import command \ No newline at end of file +from .command import command +from .callback import callback \ No newline at end of file diff --git a/misskaty/core/misskaty_patch/decorators/callback.py b/misskaty/core/misskaty_patch/decorators/callback.py new file mode 100644 index 00000000..85419d8b --- /dev/null +++ b/misskaty/core/misskaty_patch/decorators/callback.py @@ -0,0 +1,100 @@ +# tgEasy - Easy for a brighter Shine. A monkey pather add-on for Pyrogram +# Copyright (C) 2021 - 2022 Jayant Hegde Kageri + +# This file is part of tgEasy. + +# tgEasy is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# tgEasy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public License +# along with tgEasy. If not, see . + +import typing +import pyrogram +from pyrogram.methods import Decorators +from .utils import handle_error + +def callback( + self, + data: typing.Union[str, list], + self_admin: typing.Union[bool, bool] = False, + filter: typing.Union[pyrogram.filters.Filter, pyrogram.filters.Filter] = None, + *args, + **kwargs, + ): + """ + ### `Client.callback` + + - A decorater to Register Callback Quiries in simple way and manage errors in that Function itself, alternative for `@pyrogram.Client.on_callback_query(pyrogram.filters.regex('^data.*'))` + - Parameters: + - data (str || list): + - The callback query to be handled for a function + + - self_admin (bool) **optional**: + - If True, the command will only executeed if the Bot is Admin in the Chat, By Default False + + - filter (`~pyrogram.filters`) **optional**: + - Pyrogram Filters, hope you know about this, for Advaced usage. Use `and` for seaperating filters. + + #### Example + .. code-block:: python + import pyrogram + + app = pyrogram.Client() + + @app.command("start") + async def start(client, message): + await message.reply_text( + f"Hello {message.from_user.mention}", + reply_markup=pyrogram.types.InlineKeyboardMarkup([[ + pyrogram.types.InlineKeyboardButton( + "Click Here", + "data" + ) + ]]) + ) + + @app.callback("data") + async def data(client, CallbackQuery): + await CallbackQuery.answer("Hello :)", show_alert=True) + """ + if filter: + filter = pyrogram.filters.regex(f"^{data}.*") & args["filter"] + else: + filter = pyrogram.filters.regex(f"^{data}.*") + + def wrapper(func): + async def decorator(client, CallbackQuery: pyrogram.types.CallbackQuery): + if self_admin: + me = await client.get_chat_member( + CallbackQuery.message.chat.id, (await client.get_me()).id + ) + if me.status not in ( + pyrogram.enums.ChatMemberStatus.OWNER, + pyrogram.enums.ChatMemberStatus.ADMINISTRATOR, + ): + return await CallbackQuery.message.edit_text( + "I must be admin to execute this Command" + ) + try: + await func(client, CallbackQuery) + except pyrogram.errors.exceptions.forbidden_403.ChatAdminRequired: + pass + except BaseException as e: + return await handle_error(e, CallbackQuery) + + self.add_handler( + pyrogram.handlers.CallbackQueryHandler(decorator, filter) + ) + return decorator + + return wrapper + +Decorators.on_cb = callback \ No newline at end of file diff --git a/misskaty/core/misskaty_patch/decorators/command.py b/misskaty/core/misskaty_patch/decorators/command.py index 77ead0f4..886e5000 100644 --- a/misskaty/core/misskaty_patch/decorators/command.py +++ b/misskaty/core/misskaty_patch/decorators/command.py @@ -7,6 +7,7 @@ from misskaty.vars import COMMAND_HANDLER def command( self, command: typing.Union[str, list], + is_disabled: typing.Union[bool, bool] = False pm_only: typing.Union[bool, bool] = False, group_only: typing.Union[bool, bool] = False, self_admin: typing.Union[bool, bool] = False, @@ -17,7 +18,7 @@ def command( **kwargs ): """ - ### `tgEasy.tgClient.command` + ### `tgClient.command` - A decorater to Register Commands in simple way and manage errors in that Function itself, alternative for `@pyrogram.Client.on_message(pyrogram.filters.command('command'))` - Parameters: - command (str || list): @@ -44,11 +45,10 @@ def command( #### Example .. code-block:: python import pyrogram - from tgEasy import tgClient - app = tgClient(pyrogram.Client()) + app = pyrogram.Client() - @app.command("start", group_only=False, pm_only=False, self_admin=False, self_only=False, pyrogram.filters.chat("777000") and pyrogram.filters.text) + @app.command("start", is_disabled=False, group_only=False, pm_only=False, self_admin=False, self_only=False, pyrogram.filters.chat("777000") and pyrogram.filters.text) async def start(client, message): await message.reply_text(f"Hello {message.from_user.mention}") """ @@ -78,6 +78,8 @@ def command( def wrapper(func): async def decorator(client, message: pyrogram.types.Message): + if is_disabled: + return await message.reply_text("Sorry, this command has been disabled by owner.") if ( self_admin and message.chat.type != pyrogram.enums.ChatType.SUPERGROUP diff --git a/misskaty/core/misskaty_patch/utils/__init__.py b/misskaty/core/misskaty_patch/utils/__init__.py index 5f451464..bffaad9d 100644 --- a/misskaty/core/misskaty_patch/utils/__init__.py +++ b/misskaty/core/misskaty_patch/utils/__init__.py @@ -1,2 +1,4 @@ from .utils import PyromodConfig, patch, patchable -from .handle_error import handle_error \ No newline at end of file +from .handle_error import handle_error +from .admin_utils import check_rights, is_admin +from .get_user import get_user \ No newline at end of file diff --git a/misskaty/core/misskaty_patch/utils/admin_utils.py b/misskaty/core/misskaty_patch/utils/admin_utils.py new file mode 100644 index 00000000..e70ff73e --- /dev/null +++ b/misskaty/core/misskaty_patch/utils/admin_utils.py @@ -0,0 +1,154 @@ +# tgEasy - Easy for a brighter Shine. A monkey pather add-on for Pyrogram +# Copyright (C) 2021 - 2022 Jayant Hegde Kageri + +# This file is part of tgEasy. + +# tgEasy is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# tgEasy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public License +# along with tgEasy. If not, see . + +import typing +import pyrogram + + +async def check_rights( + chat_id: typing.Union[int, int], + user_id: typing.Union[int, int], + rights: typing.Union[str, list], + client, +) -> bool: + """ + ### `check_rights` + - Checks the Rights of an User + - This is an Helper Function for `adminsOnly` + + - Parameters: + - chat_id (int): + - The Chat ID of Which Chat have to check the Rights. + + - user_id (int): + - The User ID of Whose Rights have to Check. + + - rights (str): + - The Rights have to Check. + + - client (`pyrogram.Client`): + - From which Client to Check the Rights. + + - Returns: + - `True` if the User have the Right. + - `False` if the User don't have the Right. + + #### Example + .. code-block:: python + import pyrogram + + app = pyrogram.Client() + + @app.command("ban", group_only=True, self_admin=True) + async def ban(client, message): + if not await check_rights(message.chat.id, message.from_user.id, "can_restrict_members"): + return await message.reply_text("You don't have necessary rights to use this Command.") + user = await get_user(message) + await message.chat.kick_member(user.id) + """ + try: + user = await client.get_chat_member(chat_id, user_id) + except Exception: + return False + if user.status == "user": + return False + if user.status in ( + pyrogram.enums.ChatMemberStatus.OWNER, + pyrogram.enums.ChatMemberStatus.ADMINISTRATOR, + ): + permission = [] + if user.privileges.can_manage_chat: + permission.append("can_manage_chat") + + if user.privileges.can_delete_messages: + permission.append("can_delete_messages") + + if user.privileges.can_manage_video_chats: + permission.append("can_manage_video_chats") + + if user.privileges.can_restrict_members: + permission.append("can_restrict_members") + + if user.privileges.can_promote_members: + permission.append("can_promote_members") + + if user.privileges.can_change_info: + permission.append("can_change_info") + + if user.privileges.can_post_messages: + permission.append("can_post_messages") + + if user.privileges.can_edit_messages: + permission.append("can_edit_messages") + + if user.privileges.can_invite_users: + permission.append("can_invite_users") + + if user.privileges.can_pin_messages: + permission.append("can_pin_messages") + + if user.privileges.is_anonymous: + permission.append("is_anonymous") + + if isinstance(rights, str): + return rights in permission + if isinstance(rights, list): + for right in rights: + return right in permission + return False + + +async def is_admin( + chat_id: typing.Union[int, str], user_id: typing.Union[int, str], client +) -> bool: + """ + ### `is_admin` + - A Functions to Check if the User is Admin or not + + - Parameters: + - chat_id (int): + - The Chat ID of Which Chat have to check the Admin Status. + + - user_id (int): + - The User ID of Whose Admin Status have to Check. + + - client (`pyrogram.Client`): + - From which Client to Check the Admin Status. + + - Returns: + - `True` if the User is Admin. + - `False` if the User is't Admin. + #### Example + .. code-block:: python + import pyrogram + + app = pyrogram.Client() + + @app.command("ban", group_only=True, self_admin=True) + @app.adminsOnly("can_restrict_members") + async def ban(client, message): + if await is_admin(message.chat.id, (await get_user(mesasge)).id): + return await message.reply_text("You can't Ban Admins.") + await message.chat.kick_member((await get_user(message)).id) + await message.reply_text("User has been Banned.") + """ + try: + user = await client.get_chat_member(chat_id, user_id) + except Exception: + return False + return user.status in (pyrogram.enums.ChatMemberStatus.OWNER, pyrogram.enums.ChatMemberStatus.ADMINISTRATOR,) \ No newline at end of file diff --git a/misskaty/core/misskaty_patch/utils/get_user.py b/misskaty/core/misskaty_patch/utils/get_user.py new file mode 100644 index 00000000..a2a0fd1a --- /dev/null +++ b/misskaty/core/misskaty_patch/utils/get_user.py @@ -0,0 +1,122 @@ +# tgEasy - Easy for a brighter Shine. A monkey pather add-on for Pyrogram +# Copyright (C) 2021 - 2022 Jayant Hegde Kageri + +# This file is part of tgEasy. + +# tgEasy is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# tgEasy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public License +# along with tgEasy. If not, see . + +import contextlib +import typing + +import pyrogram + + +async def get_user( + m: typing.Union[pyrogram.types.Message, pyrogram.types.CallbackQuery] +) -> pyrogram.types.User or bool: + """ + ### `tgEasy.get_user` + - Gets a User from Message/RepliedMessage/CallbackQuery + - Parameters: + - m (`~pyrogram.types.Message` || `~pyrogram.types.CallbackQuery`) + - Returns: + - `pyrogram.types.User` on Success + - `False` on Error + + #### Example + .. code-block:: python + from tgEasy import get_user, command, adminsOnly + + @command("ban", group_only=True, self_admin=True) + @adminsOnly("can_restrict_members") + async def ban(client, message): + user = await get_user(message) + await message.chat.kick_member(user.id) + """ + if isinstance(m, pyrogram.types.Message): + message = m + client = m._client + if isinstance(m, pyrogram.types.CallbackQuery): + message = m.message + client = message._client + if message.reply_to_message: + if message.reply_to_message.sender_chat: + return False + return await client.get_users(message.reply_to_message.from_user.id) + + command = message.command[1] if len(message.command) > 1 else None + if command and (command.startswith("@") or command.isdigit()): + with contextlib.suppress( + pyrogram.errors.exceptions.bad_request_400.UsernameNotOccupied, + pyrogram.errors.exceptions.bad_request_400.UsernameInvalid, + pyrogram.errors.exceptions.bad_request_400.PeerIdInvalid, + IndexError, + ): + return await client.get_users(message.command[1]) + if message.entities: + for mention in message.entities: + if mention.type == "text_mention": + user = mention.user.id + break + with contextlib.suppress(Exception): + return await client.get_users(user) + return False + + +async def get_user_adv( + m: typing.Union[pyrogram.types.Message, pyrogram.types.CallbackQuery] +) -> pyrogram.types.User or bool: + """ + ### `tgEasy.get_user_adv` + - A Function to Get the User from the Message/CallbackQuery, If there is None arguments, returns the From User. + - Parameters: + - m (`pyrogram.types.Message` || `pyrogram.types.CallbackQuery`): + - Message or Callbackquery. + - Returns: + - `pyrogram.types.User` on Success + - `False` on Error + + #### Example + .. code-block:: python + from tgEasy import command, get_user_adv + + @command("id") + async def id(client, message): + user = await get_user_adv(message) + await message.reply_text(f"Your ID is `{user.id}`") + """ + if isinstance(m, pyrogram.types.Message): + message = m + if isinstance(m, pyrogram.types.CallbackQuery): + message = m.message + if message.sender_chat: + return False + with contextlib.suppress(IndexError, AttributeError): + if len(message.command) > 1: + if message.command[1].startswith("@"): + return await get_user(message) + if message.command[1].isdigit(): + return await get_user(message) + if "text_mention" in message.entities: + return await get_user(message) + if "from_user" in str(message.reply_to_message): + return await get_user(message) + with contextlib.suppress(Exception): + if "sender_chat" in str(message.reply_to_message): + return False + if "from_user" in str(message.reply_to_message): + return await message._client.get_users( + message.reply_to_message.from_user.id + ) + return await message._client.get_users(message.from_user.id) \ No newline at end of file diff --git a/misskaty/core/misskaty_patch/utils/handler_error.py b/misskaty/core/misskaty_patch/utils/handler_error.py index 186421cc..7cd647a9 100644 --- a/misskaty/core/misskaty_patch/utils/handler_error.py +++ b/misskaty/core/misskaty_patch/utils/handler_error.py @@ -19,6 +19,7 @@ import contextlib import os import typing import pyrogram +from datetime import datetime from misskaty.vars import LOG_CHANNEL @@ -40,7 +41,6 @@ async def handle_error( #### Exapmle .. code-block:: python - from tgEasy import tgClient, handle_error import pyrogram app = tgClient(pyrogram.Client()) @@ -58,6 +58,10 @@ async def handle_error( logging = logger.getLogger(__name__) logging.exception(traceback.format_exc()) + day = datetime.now() + tgl_now = datetime.now() + cap_day = f"{day.strftime('%A')}, {tgl_now.strftime('%d %B %Y %H:%M:%S')}" + with open("crash.txt", "w+", encoding="utf-8") as log: log.write(traceback.format_exc()) log.close() @@ -67,7 +71,7 @@ async def handle_error( "An Internal Error Occurred while Processing your Command, the Logs have been sent to the Owners of this Bot. Sorry for Inconvenience" ) await m._client.send_document( - LOG_CHANNEL, "crash.txt", caption="Crash Report of this Bot" + LOG_CHANNEL, crash_{tgl_now.strftime('%d %B %Y')}.txt, caption="Crash Report of this Bot\n{cap_day}" ) if isinstance(m, pyrogram.types.CallbackQuery): with contextlib.suppress(Exception): @@ -76,7 +80,7 @@ async def handle_error( "An Internal Error Occurred while Processing your Command, the Logs have been sent to the Owners of this Bot. Sorry for Inconvenience" ) await m.message._client.send_document( - LOG_CHANNEL, "crash.txt", caption="Crash Report of this Bot" + LOG_CHANNEL, crash_{tgl_now.strftime('%d %B %Y')}.txt, caption="Crash Report of this Bot\n{cap_day}" ) - os.remove("crash.txt") + os.remove(crash_{tgl_now.strftime('%d %B %Y')}.txt) return True \ No newline at end of file diff --git a/misskaty/plugins/chatbot_ai.py b/misskaty/plugins/chatbot_ai.py index c34ae3aa..27e488a6 100644 --- a/misskaty/plugins/chatbot_ai.py +++ b/misskaty/plugins/chatbot_ai.py @@ -22,7 +22,7 @@ openai.api_key = OPENAI_API # This only for testing things, since maybe in future it will got blocked -@app.on_message(filters.command("bard", COMMAND_HANDLER)) +@app.on_cmd("bard", is_disabled=True) @use_chat_lang() async def bard_chatbot(self: Client, ctx: Message, strings): if len(ctx.command) == 1: diff --git a/misskaty/plugins/subscene_dl.py b/misskaty/plugins/subscene_dl.py index 7dc14a37..d9a57463 100644 --- a/misskaty/plugins/subscene_dl.py +++ b/misskaty/plugins/subscene_dl.py @@ -37,7 +37,7 @@ async def getTitleSub(msg, kueri, CurrentPage, user): lists = soup.find("div", {"class": "search-result"}) entry = lists.find_all("div", {"class": "title"}) # if "Tidak Ditemukan" in entry[0].text: - # await editPesan(msg, f"Sorry, could not find any result for: {kueri}") + # await msg.edit_msg(f"Sorry, could not find any result for: {kueri}") # return None, 0, None for sub in entry: title = sub.find("a").text