mirror of https://github.com/coddrago/Heroku
1045 lines
35 KiB
Python
1045 lines
35 KiB
Python
# ©️ 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
|
|
|
|
# ©️ Codrago, 2024-2025
|
|
# This file is a part of Heroku Userbot
|
|
# 🌐 https://github.com/coddrago/Heroku
|
|
# 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 herokutl.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 HerokuConfigMod(loader.Module):
|
|
"""Interactive configurator for Heroku Userbot"""
|
|
|
|
strings = {"name": "HerokuConfig"}
|
|
|
|
def __init__(self):
|
|
self.config = loader.ModuleConfig(
|
|
loader.ConfigValue(
|
|
"cfg_emoji",
|
|
"🪐",
|
|
"Change emoji when opening config",
|
|
validator=loader.validators.String(),
|
|
),
|
|
)
|
|
|
|
@staticmethod
|
|
def prep_value(value: typing.Any) -> typing.Any:
|
|
if isinstance(value, str):
|
|
return f"</b><code>{utils.escape_html(value.strip())}</code><b>"
|
|
|
|
if isinstance(value, list) and value:
|
|
return (
|
|
"</b><code>[</code>\n "
|
|
+ "\n ".join(
|
|
[f"<code>{utils.escape_html(str(item))}</code>" for item in value]
|
|
)
|
|
+ "\n<code>]</code><b>"
|
|
)
|
|
|
|
return f"</b><code>{utils.escape_html(value)}</code><b>"
|
|
|
|
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(
|
|
[
|
|
"▫️ <code>{}</code>: <b>{}</b>".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("<core") or not obj_type)
|
|
and (not mod.__origin__.startswith("<core") or obj_type)
|
|
]
|
|
else:
|
|
to_config = [
|
|
lib.name for lib in self.allmodules.libraries if hasattr(lib, "config")
|
|
]
|
|
|
|
to_config.sort()
|
|
|
|
kb = []
|
|
for mod_row in utils.chunks(
|
|
to_config[page * NUM_ROWS * ROW_SIZE : (page + 1) * NUM_ROWS * ROW_SIZE],
|
|
3,
|
|
):
|
|
row = [
|
|
{
|
|
"text": btn,
|
|
"callback": self.inline__configure,
|
|
"args": (btn,),
|
|
"kwargs": {"obj_type": obj_type},
|
|
}
|
|
for btn in mod_row
|
|
]
|
|
kb += [row]
|
|
|
|
if len(to_config) > 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)
|
|
args_s = args.split()
|
|
if len(args_s) == 1 and self.lookup(args_s[0]) and hasattr(self.lookup(args_s[0]), 'config'):
|
|
form = await self.inline.form(self.config["cfg_emoji"], message, silent=True)
|
|
mod = self.lookup(args)
|
|
if isinstance(mod, loader.Library):
|
|
type_ = "library"
|
|
else:
|
|
type_ = mod.__origin__.startswith("<core")
|
|
|
|
await self.inline__configure(form, args, obj_type=type_)
|
|
return
|
|
|
|
if len(args_s) == 2 and self.lookup(args_s[0]) and hasattr(self.lookup(args_s[0]), 'config'):
|
|
form = await self.inline.form(self.config["cfg_emoji"], message, silent=True)
|
|
mod = self.lookup(args_s[0])
|
|
if isinstance(mod, loader.Library):
|
|
type_ = "library"
|
|
else:
|
|
type_ = mod.__origin__.startswith("<core")
|
|
|
|
if args_s[1] in mod.config.keys():
|
|
await self.inline__configure_option(form, args_s[0], args_s[1], obj_type=type_)
|
|
else:
|
|
await self.inline__configure(form, args, obj_type=type_)
|
|
return
|
|
|
|
await self.inline__choose_category(message)
|
|
|
|
@loader.command(alias="fcfg")
|
|
async def fconfig(self, message: Message):
|
|
args = utils.get_args_raw(message).split(maxsplit=2)
|
|
|
|
if len(args) < 3:
|
|
await utils.answer(message, self.strings("args"))
|
|
return
|
|
|
|
mod, option, value = args
|
|
|
|
if not (instance := self.lookup(mod)):
|
|
await utils.answer(message, self.strings("no_mod"))
|
|
return
|
|
|
|
if option not in instance.config:
|
|
await utils.answer(message, self.strings("no_option"))
|
|
return
|
|
|
|
instance.config[option] = value
|
|
await utils.answer(
|
|
message,
|
|
self.strings(
|
|
"option_saved"
|
|
if isinstance(instance, loader.Module)
|
|
else "option_saved_lib"
|
|
).format(
|
|
utils.escape_html(option),
|
|
utils.escape_html(mod),
|
|
self._get_value(mod, option),
|
|
),
|
|
)
|