123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- # ©️ 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 difflib
- import inspect
- import logging
- from hikkatl.extensions.html import CUSTOM_EMOJIS
- from hikkatl.tl.types import Message
- from .. import loader, utils
- from ..compat.dragon import DRAGON_EMOJI
- from ..types import DragonModule
- logger = logging.getLogger(__name__)
- @loader.tds
- class Help(loader.Module):
- """Shows help for modules and commands"""
- strings = {"name": "Help"}
- def __init__(self):
- self.config = loader.ModuleConfig(
- loader.ConfigValue(
- "core_emoji",
- "▪️",
- lambda: "Core module bullet",
- validator=loader.validators.Emoji(length=1),
- ),
- loader.ConfigValue(
- "plain_emoji",
- "▫️",
- lambda: "Plain module bullet",
- validator=loader.validators.Emoji(length=1),
- ),
- loader.ConfigValue(
- "empty_emoji",
- "🙈",
- lambda: "Empty modules bullet",
- validator=loader.validators.Emoji(length=1),
- ),
- )
- @loader.command()
- async def helphide(self, message: Message):
- if not (modules := utils.get_args(message)):
- await utils.answer(message, self.strings("no_mod"))
- return
- currently_hidden = self.get("hide", [])
- hidden, shown = [], []
- for module in filter(
- lambda module: self.lookup(module, include_dragon=True), modules
- ):
- module = self.lookup(module, include_dragon=True)
- module = (
- module.name
- if isinstance(module, DragonModule)
- else module.__class__.__name__
- )
- if module in currently_hidden:
- currently_hidden.remove(module)
- shown += [module]
- else:
- currently_hidden += [module]
- hidden += [module]
- self.set("hide", currently_hidden)
- await utils.answer(
- message,
- self.strings("hidden_shown").format(
- len(hidden),
- len(shown),
- "\n".join([f"👁🗨 <i>{m}</i>" for m in hidden]),
- "\n".join([f"👁 <i>{m}</i>" for m in shown]),
- ),
- )
- def find_aliases(self, command: str) -> list:
- """Find aliases for command"""
- aliases = []
- _command = self.allmodules.commands[command]
- if getattr(_command, "alias", None) and not (
- aliases := getattr(_command, "aliases", None)
- ):
- aliases = [_command.alias]
- return aliases or []
- async def modhelp(self, message: Message, args: str):
- exact = True
- if not (module := self.lookup(args, include_dragon=True)):
- if method := self.allmodules.dispatch(
- args.lower().strip(self.get_prefix())
- )[1]:
- module = method.__self__
- else:
- module = self.lookup(
- next(
- (
- reversed(
- sorted(
- [
- module.strings["name"]
- for module in self.allmodules.modules
- ],
- key=lambda x: difflib.SequenceMatcher(
- None,
- args.lower(),
- x,
- ).ratio(),
- )
- )
- ),
- None,
- )
- )
- exact = False
- is_dragon = isinstance(module, DragonModule)
- try:
- name = module.strings("name")
- except (KeyError, AttributeError):
- name = getattr(module, "name", "ERROR")
- _name = (
- "{} (v{}.{}.{})".format(
- utils.escape_html(name),
- module.__version__[0],
- module.__version__[1],
- module.__version__[2],
- )
- if hasattr(module, "__version__")
- else utils.escape_html(name)
- )
- reply = "{} <b>{}</b>:".format(
- (
- DRAGON_EMOJI
- if is_dragon
- else "<emoji document_id=5188377234380954537>🌘</emoji>"
- ),
- _name,
- )
- if module.__doc__:
- reply += (
- "<i>\n<emoji document_id=5787544344906959608>ℹ️</emoji> "
- + utils.escape_html(inspect.getdoc(module))
- + "\n</i>"
- )
- commands = (
- module.commands
- if is_dragon
- else {
- name: func
- for name, func in module.commands.items()
- if await self.allmodules.check_security(message, func)
- }
- )
- if hasattr(module, "inline_handlers") and not is_dragon:
- for name, fun in module.inline_handlers.items():
- reply += (
- "\n<emoji document_id=5372981976804366741>🤖</emoji>"
- " <code>{}</code> {}".format(
- f"@{self.inline.bot_username} {name}",
- (
- utils.escape_html(inspect.getdoc(fun))
- if fun.__doc__
- else self.strings("undoc")
- ),
- )
- )
- for name, fun in commands.items():
- reply += (
- "\n<emoji document_id=4971987363145188045>▫️</emoji>"
- " <code>{}{}</code>{} {}".format(
- utils.escape_html(self.get_prefix("dragon" if is_dragon else None)),
- name,
- (
- " ({})".format(
- ", ".join(
- "<code>{}{}</code>".format(
- utils.escape_html(
- self.get_prefix("dragon" if is_dragon else None)
- ),
- alias,
- )
- for alias in self.find_aliases(name)
- )
- )
- if self.find_aliases(name)
- else ""
- ),
- (
- utils.escape_html(fun)
- if is_dragon
- else (
- utils.escape_html(inspect.getdoc(fun))
- if fun.__doc__
- else self.strings("undoc")
- )
- ),
- )
- )
- await utils.answer(
- message,
- reply
- + (f"\n\n{self.strings('not_exact')}" if not exact else "")
- + (
- f"\n\n{self.strings('core_notice')}"
- if module.__origin__.startswith("<core")
- else ""
- ),
- )
- @loader.command()
- async def help(self, message: Message):
- args = utils.get_args_raw(message)
- force = False
- if "-f" in args:
- args = args.replace(" -f", "").replace("-f", "")
- force = True
- if args:
- await self.modhelp(message, args)
- return
- hidden = self.get("hide", [])
- reply = self.strings("all_header").format(
- len(self.allmodules.modules) + len(self.allmodules.dragon_modules),
- (
- 0
- if force
- else sum(
- module.__class__.__name__ in hidden
- for module in self.allmodules.modules
- )
- + sum(
- module.name in hidden for module in self.allmodules.dragon_modules
- )
- ),
- )
- shown_warn = False
- plain_ = []
- core_ = []
- no_commands_ = []
- dragon_ = []
- for mod in self.allmodules.dragon_modules:
- if mod.name in self.get("hide", []) and not force:
- continue
- tmp = "\n{} <code>{}</code>".format(DRAGON_EMOJI, mod.name)
- first = True
- for cmd in mod.commands:
- cmd = cmd.split()[0]
- if first:
- tmp += f": ( {cmd}"
- first = False
- else:
- tmp += f" | {cmd}"
- dragon_ += [tmp + " )"]
- for mod in self.allmodules.modules:
- if not hasattr(mod, "commands"):
- logger.debug("Module %s is not inited yet", mod.__class__.__name__)
- continue
- if mod.__class__.__name__ in self.get("hide", []) and not force:
- continue
- tmp = ""
- try:
- name = mod.strings["name"]
- except KeyError:
- name = getattr(mod, "name", "ERROR")
- if (
- not getattr(mod, "commands", None)
- and not getattr(mod, "inline_handlers", None)
- and not getattr(mod, "callback_handlers", None)
- ):
- no_commands_ += [
- "\n{} <code>{}</code>".format(self.config["empty_emoji"], name)
- ]
- continue
- core = mod.__origin__.startswith("<core")
- tmp += "\n{} <code>{}</code>".format(
- self.config["core_emoji"] if core else self.config["plain_emoji"], name
- )
- first = True
- commands = [
- name
- for name, func in mod.commands.items()
- if await self.allmodules.check_security(message, func) or force
- ]
- for cmd in commands:
- if first:
- tmp += f": ( {cmd}"
- first = False
- else:
- tmp += f" | {cmd}"
- icommands = [
- name
- for name, func in mod.inline_handlers.items()
- if await self.inline.check_inline_security(
- func=func,
- user=message.sender_id,
- )
- or force
- ]
- for cmd in icommands:
- if first:
- tmp += f": ( 🤖 {cmd}"
- first = False
- else:
- tmp += f" | 🤖 {cmd}"
- if commands or icommands:
- tmp += " )"
- if core:
- core_ += [tmp]
- else:
- plain_ += [tmp]
- elif not shown_warn and (mod.commands or mod.inline_handlers):
- reply = (
- "<i>You have permissions to execute only these"
- f" commands</i>\n{reply}"
- )
- shown_warn = True
- plain_.sort(key=lambda x: x.split()[1])
- core_.sort(key=lambda x: x.split()[1])
- no_commands_.sort(key=lambda x: x.split()[1])
- dragon_.sort()
- await utils.answer(
- message,
- "{}\n{}{}".format(
- reply,
- "".join(core_ + plain_ + dragon_ + (no_commands_ if force else [])),
- (
- ""
- if self.lookup("Loader").fully_loaded
- else f"\n\n{self.strings('partial_load')}"
- ),
- ),
- )
- @loader.command()
- async def support(self, message):
- if message.out:
- await self.request_join("@hikka_talks", self.strings("request_join"))
- await utils.answer(
- message,
- self.strings("support").format(
- (
- utils.get_platform_emoji()
- if self._client.hikka_me.premium and CUSTOM_EMOJIS
- else "🌘"
- )
- ),
- )
|