diff --git a/hikka/modules/hikka_config.py b/hikka/modules/hikka_config.py deleted file mode 100644 index 45d2515..0000000 --- a/hikka/modules/hikka_config.py +++ /dev/null @@ -1,1013 +0,0 @@ -# ÂŠī¸ Dan Gazizullin, 2021-2023 -# This file is a part of Hikka Userbot -# 🌐 https://github.com/hikariatama/Hikka -# You can redistribute it and/or modify it under the terms of the GNU AGPLv3 -# 🔑 https://www.gnu.org/licenses/agpl-3.0.html - -import ast -import contextlib -import functools -import typing -from math import ceil - -from hikkatl.tl.types import Message - -from .. import loader, translations, utils -from ..inline.types import InlineCall - -# Everywhere in this module, we use the following naming convention: -# `obj_type` of non-core module = False -# `obj_type` of core module = True -# `obj_type` of library = "library" - - -ROW_SIZE = 3 -NUM_ROWS = 5 - - -@loader.tds -class HikkaConfigMod(loader.Module): - """Interactive configurator for Hikka Userbot""" - - strings = {"name": "HerokuConfig"} - - @staticmethod - def prep_value(value: typing.Any) -> typing.Any: - if isinstance(value, str): - return f"{utils.escape_html(value.strip())}" - - if isinstance(value, list) and value: - return ( - "[\n " - + "\n ".join( - [f"{utils.escape_html(str(item))}" for item in value] - ) - + "\n]" - ) - - return f"{utils.escape_html(value)}" - - def hide_value(self, value: typing.Any) -> str: - if isinstance(value, list) and value: - return self.prep_value(["*" * len(str(i)) for i in value]) - - return self.prep_value("*" * len(str(value))) - - def _get_value(self, mod: str, option: str) -> str: - return ( - self.prep_value(self.lookup(mod).config[option]) - if ( - not self.lookup(mod).config._config[option].validator - or self.lookup(mod).config._config[option].validator.internal_id - != "Hidden" - ) - else self.hide_value(self.lookup(mod).config[option]) - ) - - async def inline__set_config( - self, - call: InlineCall, - query: str, - mod: str, - option: str, - inline_message_id: str, - obj_type: typing.Union[bool, str] = False, - ): - try: - self.lookup(mod).config[option] = query - except loader.validators.ValidationError as e: - await call.edit( - self.strings("validation_error").format(e.args[0]), - reply_markup={ - "text": self.strings("try_again"), - "callback": self.inline__configure_option, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - }, - ) - return - - await call.edit( - self.strings( - "option_saved" if isinstance(obj_type, bool) else "option_saved_lib" - ).format( - utils.escape_html(option), - utils.escape_html(mod), - self._get_value(mod, option), - ), - reply_markup=[ - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ] - ], - inline_message_id=inline_message_id, - ) - - async def inline__reset_default( - self, - call: InlineCall, - mod: str, - option: str, - obj_type: typing.Union[bool, str] = False, - ): - mod_instance = self.lookup(mod) - mod_instance.config[option] = mod_instance.config.getdef(option) - - await call.edit( - self.strings( - "option_reset" if isinstance(obj_type, bool) else "option_reset_lib" - ).format( - utils.escape_html(option), - utils.escape_html(mod), - self._get_value(mod, option), - ), - reply_markup=[ - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ] - ], - ) - - async def inline__set_bool( - self, - call: InlineCall, - mod: str, - option: str, - value: bool, - obj_type: typing.Union[bool, str] = False, - ): - try: - self.lookup(mod).config[option] = value - except loader.validators.ValidationError as e: - await call.edit( - self.strings("validation_error").format(e.args[0]), - reply_markup={ - "text": self.strings("try_again"), - "callback": self.inline__configure_option, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - }, - ) - return - - validator = self.lookup(mod).config._config[option].validator - doc = utils.escape_html( - next( - ( - validator.doc[lang] - for lang in self._db.get(translations.__name__, "lang", "en").split( - " " - ) - if lang in validator.doc - ), - validator.doc["en"], - ) - ) - - await call.edit( - self.strings( - "configuring_option" - if isinstance(obj_type, bool) - else "configuring_option_lib" - ).format( - utils.escape_html(option), - utils.escape_html(mod), - utils.escape_html(self.lookup(mod).config.getdoc(option)), - self.prep_value(self.lookup(mod).config.getdef(option)), - ( - self.prep_value(self.lookup(mod).config[option]) - if not validator or validator.internal_id != "Hidden" - else self.hide_value(self.lookup(mod).config[option]) - ), - ( - self.strings("typehint").format( - doc, - eng_art="n" if doc.lower().startswith(tuple("euioay")) else "", - ) - if doc - else "" - ), - ), - reply_markup=self._generate_bool_markup(mod, option, obj_type), - ) - - await call.answer("✅") - - def _generate_bool_markup( - self, - mod: str, - option: str, - obj_type: typing.Union[bool, str] = False, - ) -> list: - return [ - [ - *( - [ - { - "text": f"❌ {self.strings('set')} `False`", - "callback": self.inline__set_bool, - "args": (mod, option, False), - "kwargs": {"obj_type": obj_type}, - } - ] - if self.lookup(mod).config[option] - else [ - { - "text": f"✅ {self.strings('set')} `True`", - "callback": self.inline__set_bool, - "args": (mod, option, True), - "kwargs": {"obj_type": obj_type}, - } - ] - ) - ], - [ - *( - [ - { - "text": self.strings("set_default_btn"), - "callback": self.inline__reset_default, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - } - ] - if self.lookup(mod).config[option] - != self.lookup(mod).config.getdef(option) - else [] - ) - ], - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ], - ] - - async def inline__add_item( - self, - call: InlineCall, - query: str, - mod: str, - option: str, - inline_message_id: str, - obj_type: typing.Union[bool, str] = False, - ): - try: - with contextlib.suppress(Exception): - query = ast.literal_eval(query) - - if isinstance(query, (set, tuple)): - query = list(query) - - if not isinstance(query, list): - query = [query] - - self.lookup(mod).config[option] = self.lookup(mod).config[option] + query - except loader.validators.ValidationError as e: - await call.edit( - self.strings("validation_error").format(e.args[0]), - reply_markup={ - "text": self.strings("try_again"), - "callback": self.inline__configure_option, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - }, - ) - return - - await call.edit( - self.strings( - "option_saved" if isinstance(obj_type, bool) else "option_saved_lib" - ).format( - utils.escape_html(option), - utils.escape_html(mod), - self._get_value(mod, option), - ), - reply_markup=[ - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ] - ], - inline_message_id=inline_message_id, - ) - - async def inline__remove_item( - self, - call: InlineCall, - query: str, - mod: str, - option: str, - inline_message_id: str, - obj_type: typing.Union[bool, str] = False, - ): - try: - with contextlib.suppress(Exception): - query = ast.literal_eval(query) - - if isinstance(query, (set, tuple)): - query = list(query) - - if not isinstance(query, list): - query = [query] - - query = list(map(str, query)) - - old_config_len = len(self.lookup(mod).config[option]) - - self.lookup(mod).config[option] = [ - i for i in self.lookup(mod).config[option] if str(i) not in query - ] - - if old_config_len == len(self.lookup(mod).config[option]): - raise loader.validators.ValidationError( - f"Nothing from passed value ({self.prep_value(query)}) is not in" - " target list" - ) - except loader.validators.ValidationError as e: - await call.edit( - self.strings("validation_error").format(e.args[0]), - reply_markup={ - "text": self.strings("try_again"), - "callback": self.inline__configure_option, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - }, - ) - return - - await call.edit( - self.strings( - "option_saved" if isinstance(obj_type, bool) else "option_saved_lib" - ).format( - utils.escape_html(option), - utils.escape_html(mod), - self._get_value(mod, option), - ), - reply_markup=[ - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ] - ], - inline_message_id=inline_message_id, - ) - - def _generate_series_markup( - self, - call: InlineCall, - mod: str, - option: str, - obj_type: typing.Union[bool, str] = False, - ) -> list: - return [ - [ - { - "text": self.strings("enter_value_btn"), - "input": self.strings("enter_value_desc"), - "handler": self.inline__set_config, - "args": (mod, option, call.inline_message_id), - "kwargs": {"obj_type": obj_type}, - } - ], - [ - *( - [ - { - "text": self.strings("remove_item_btn"), - "input": self.strings("remove_item_desc"), - "handler": self.inline__remove_item, - "args": (mod, option, call.inline_message_id), - "kwargs": {"obj_type": obj_type}, - }, - { - "text": self.strings("add_item_btn"), - "input": self.strings("add_item_desc"), - "handler": self.inline__add_item, - "args": (mod, option, call.inline_message_id), - "kwargs": {"obj_type": obj_type}, - }, - ] - if self.lookup(mod).config[option] - else [] - ), - ], - [ - *( - [ - { - "text": self.strings("set_default_btn"), - "callback": self.inline__reset_default, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - } - ] - if self.lookup(mod).config[option] - != self.lookup(mod).config.getdef(option) - else [] - ) - ], - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ], - ] - - async def _choice_set_value( - self, - call: InlineCall, - mod: str, - option: str, - value: bool, - obj_type: typing.Union[bool, str] = False, - ): - try: - self.lookup(mod).config[option] = value - except loader.validators.ValidationError as e: - await call.edit( - self.strings("validation_error").format(e.args[0]), - reply_markup={ - "text": self.strings("try_again"), - "callback": self.inline__configure_option, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - }, - ) - return - - await call.edit( - self.strings( - "option_saved" if isinstance(obj_type, bool) else "option_saved_lib" - ).format( - utils.escape_html(option), - utils.escape_html(mod), - self._get_value(mod, option), - ), - reply_markup=[ - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ] - ], - ) - - await call.answer("✅") - - async def _multi_choice_set_value( - self, - call: InlineCall, - mod: str, - option: str, - value: bool, - obj_type: typing.Union[bool, str] = False, - ): - try: - if value in self.lookup(mod).config._config[option].value: - self.lookup(mod).config._config[option].value.remove(value) - else: - self.lookup(mod).config._config[option].value += [value] - - self.lookup(mod).config.reload() - except loader.validators.ValidationError as e: - await call.edit( - self.strings("validation_error").format(e.args[0]), - reply_markup={ - "text": self.strings("try_again"), - "callback": self.inline__configure_option, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - }, - ) - return - - await self.inline__configure_option(call, mod, option, False, obj_type) - await call.answer("✅") - - def _generate_choice_markup( - self, - call: InlineCall, - mod: str, - option: str, - obj_type: typing.Union[bool, str] = False, - ) -> list: - possible_values = list( - self.lookup(mod) - .config._config[option] - .validator.validate.keywords["possible_values"] - ) - return [ - [ - { - "text": self.strings("enter_value_btn"), - "input": self.strings("enter_value_desc"), - "handler": self.inline__set_config, - "args": (mod, option, call.inline_message_id), - "kwargs": {"obj_type": obj_type}, - } - ], - *utils.chunks( - [ - { - "text": ( - f"{'â˜‘ī¸' if self.lookup(mod).config[option] == value else '🔘'} " - f"{value if len(str(value)) < 20 else str(value)[:20]}" - ), - "callback": self._choice_set_value, - "args": (mod, option, value, obj_type), - } - for value in possible_values - ], - 2, - )[ - : ( - 6 - if self.lookup(mod).config[option] - != self.lookup(mod).config.getdef(option) - else 7 - ) - ], - [ - *( - [ - { - "text": self.strings("set_default_btn"), - "callback": self.inline__reset_default, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - } - ] - if self.lookup(mod).config[option] - != self.lookup(mod).config.getdef(option) - else [] - ) - ], - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ], - ] - - def _generate_multi_choice_markup( - self, - call: InlineCall, - mod: str, - option: str, - obj_type: typing.Union[bool, str] = False, - ) -> list: - possible_values = list( - self.lookup(mod) - .config._config[option] - .validator.validate.keywords["possible_values"] - ) - return [ - [ - { - "text": self.strings("enter_value_btn"), - "input": self.strings("enter_value_desc"), - "handler": self.inline__set_config, - "args": (mod, option, call.inline_message_id), - "kwargs": {"obj_type": obj_type}, - } - ], - *utils.chunks( - [ - { - "text": ( - f"{'â˜‘ī¸' if value in self.lookup(mod).config[option] else 'â—ģī¸'} " - f"{value if len(str(value)) < 20 else str(value)[:20]}" - ), - "callback": self._multi_choice_set_value, - "args": (mod, option, value, obj_type), - } - for value in possible_values - ], - 2, - )[ - : ( - 6 - if self.lookup(mod).config[option] - != self.lookup(mod).config.getdef(option) - else 7 - ) - ], - [ - *( - [ - { - "text": self.strings("set_default_btn"), - "callback": self.inline__reset_default, - "args": (mod, option), - "kwargs": {"obj_type": obj_type}, - } - ] - if self.lookup(mod).config[option] - != self.lookup(mod).config.getdef(option) - else [] - ) - ], - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ], - ] - - async def inline__configure_option( - self, - call: InlineCall, - mod: str, - config_opt: str, - force_hidden: bool = False, - obj_type: typing.Union[bool, str] = False, - ): - module = self.lookup(mod) - args = [ - utils.escape_html(config_opt), - utils.escape_html(mod), - utils.escape_html(module.config.getdoc(config_opt)), - self.prep_value(module.config.getdef(config_opt)), - ( - self.prep_value(module.config[config_opt]) - if not module.config._config[config_opt].validator - or module.config._config[config_opt].validator.internal_id != "Hidden" - or force_hidden - else self.hide_value(module.config[config_opt]) - ), - ] - - if ( - module.config._config[config_opt].validator - and module.config._config[config_opt].validator.internal_id == "Hidden" - ): - additonal_button_row = ( - [ - [ - { - "text": self.strings("hide_value"), - "callback": self.inline__configure_option, - "args": (mod, config_opt, False), - "kwargs": {"obj_type": obj_type}, - } - ] - ] - if force_hidden - else [ - [ - { - "text": self.strings("show_hidden"), - "callback": self.inline__configure_option, - "args": (mod, config_opt, True), - "kwargs": {"obj_type": obj_type}, - } - ] - ] - ) - else: - additonal_button_row = [] - - try: - validator = module.config._config[config_opt].validator - doc = utils.escape_html( - next( - ( - validator.doc[lang] - for lang in self._db.get( - translations.__name__, "lang", "en" - ).split(" ") - if lang in validator.doc - ), - validator.doc["en"], - ) - ) - except Exception: - doc = None - validator = None - args += [""] - else: - args += [ - self.strings("typehint").format( - doc, - eng_art="n" if doc.lower().startswith(tuple("euioay")) else "", - ) - ] - if validator.internal_id == "Boolean": - await call.edit( - self.strings( - "configuring_option" - if isinstance(obj_type, bool) - else "configuring_option_lib" - ).format(*args), - reply_markup=additonal_button_row - + self._generate_bool_markup(mod, config_opt, obj_type), - ) - return - - if validator.internal_id == "Series": - await call.edit( - self.strings( - "configuring_option" - if isinstance(obj_type, bool) - else "configuring_option_lib" - ).format(*args), - reply_markup=additonal_button_row - + self._generate_series_markup(call, mod, config_opt, obj_type), - ) - return - - if validator.internal_id == "Choice": - await call.edit( - self.strings( - "configuring_option" - if isinstance(obj_type, bool) - else "configuring_option_lib" - ).format(*args), - reply_markup=additonal_button_row - + self._generate_choice_markup(call, mod, config_opt, obj_type), - ) - return - - if validator.internal_id == "MultiChoice": - await call.edit( - self.strings( - "configuring_option" - if isinstance(obj_type, bool) - else "configuring_option_lib" - ).format(*args), - reply_markup=additonal_button_row - + self._generate_multi_choice_markup( - call, mod, config_opt, obj_type - ), - ) - return - - await call.edit( - self.strings( - "configuring_option" - if isinstance(obj_type, bool) - else "configuring_option_lib" - ).format(*args), - reply_markup=additonal_button_row - + [ - [ - { - "text": self.strings("enter_value_btn"), - "input": self.strings("enter_value_desc"), - "handler": self.inline__set_config, - "args": (mod, config_opt, call.inline_message_id), - "kwargs": {"obj_type": obj_type}, - } - ], - [ - { - "text": self.strings("set_default_btn"), - "callback": self.inline__reset_default, - "args": (mod, config_opt), - "kwargs": {"obj_type": obj_type}, - } - ], - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__configure, - "args": (mod,), - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ], - ], - ) - - async def inline__configure( - self, - call: InlineCall, - mod: str, - obj_type: typing.Union[bool, str] = False, - ): - btns = [ - { - "text": param, - "callback": self.inline__configure_option, - "args": (mod, param), - "kwargs": {"obj_type": obj_type}, - } - for param in self.lookup(mod).config - ] - - await call.edit( - self.strings( - "configuring_mod" if isinstance(obj_type, bool) else "configuring_lib" - ).format( - utils.escape_html(mod), - "\n".join( - [ - "â–Ģī¸ {}: {}".format( - utils.escape_html(key), - self._get_value(mod, key), - ) - for key in self.lookup(mod).config - ] - ), - ), - reply_markup=list(utils.chunks(btns, 2)) - + [ - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__global_config, - "kwargs": {"obj_type": obj_type}, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ] - ], - ) - - async def inline__choose_category(self, call: typing.Union[Message, InlineCall]): - await utils.answer( - call, - self.strings("choose_core"), - reply_markup=[ - [ - { - "text": self.strings("builtin"), - "callback": self.inline__global_config, - "kwargs": {"obj_type": True}, - }, - { - "text": self.strings("external"), - "callback": self.inline__global_config, - }, - ], - *( - [ - [ - { - "text": self.strings("libraries"), - "callback": self.inline__global_config, - "kwargs": {"obj_type": "library"}, - } - ] - ] - if self.allmodules.libraries - and any(hasattr(lib, "config") for lib in self.allmodules.libraries) - else [] - ), - [{"text": self.strings("close_btn"), "action": "close"}], - ], - ) - - async def inline__global_config( - self, - call: InlineCall, - page: int = 0, - obj_type: typing.Union[bool, str] = False, - ): - if isinstance(obj_type, bool): - to_config = [ - mod.strings("name") - for mod in self.allmodules.modules - if hasattr(mod, "config") - and callable(mod.strings) - and (mod.__origin__.startswith(" NUM_ROWS * ROW_SIZE: - kb += self.inline.build_pagination( - callback=functools.partial( - self.inline__global_config, obj_type=obj_type - ), - total_pages=ceil(len(to_config) / (NUM_ROWS * ROW_SIZE)), - current_page=page + 1, - ) - - kb += [ - [ - { - "text": self.strings("back_btn"), - "callback": self.inline__choose_category, - }, - {"text": self.strings("close_btn"), "action": "close"}, - ] - ] - - await call.edit( - self.strings( - "configure" if isinstance(obj_type, bool) else "configure_lib" - ), - reply_markup=kb, - ) - - @loader.command(alias="cfg") - async def configcmd(self, message: Message): - args = utils.get_args_raw(message) - if self.lookup(args) and hasattr(self.lookup(args), "config"): - form = await self.inline.form("đŸĒ", message, silent=True) - mod = self.lookup(args) - if isinstance(mod, loader.Library): - type_ = "library" - else: - type_ = mod.__origin__.startswith("