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("