# █ █ ▀ █▄▀ ▄▀█ █▀█ ▀ ▄▀█ ▀█▀ ▄▀█ █▀▄▀█ ▄▀█
# █▀█ █ █ █ █▀█ █▀▄ █ ▄ █▀█ █ █▀█ █ ▀ █ █▀█
#
# © Copyright 2022
#
# https://t.me/hikariatama
#
# 🔒 Licensed under the GNU GPLv3
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
# scope: inline
import time
import logging
from io import BytesIO
from .. import loader, utils, main
from typing import Union
from telethon.tl.types import Message
from telethon.errors.rpcerrorlist import ChatSendInlineForbiddenError
import aiogram
logger = logging.getLogger(__name__)
@loader.tds
class TestMod(loader.Module):
"""Perform operations based on userbot self-testing"""
strings = {
"name": "Tester",
"set_loglevel": "🚫 Please specify verbosity as an integer or string",
"no_logs": "ℹ️ You don't have any logs at verbosity {}.",
"logs_filename": "hikka-logs.txt",
"logs_caption": "🏩 Hikka logs with verbosity {}
\n\n👩🎤 Hikka version: {}.{}.{}\n⏱ Uptime: {}\n{}",
"suspend_invalid_time": "🚫 Invalid time to suspend",
"suspended": "🥶 Bot suspended for {}
seconds",
"results_ping": "⏱ Ping: {}
ms",
"confidential": "⚠️ Log level {}
may reveal your confidential info, be careful",
"confidential_text": "⚠️ Log level {0}
may reveal your confidential info, be careful\nType .logs {0} force_insecure
to ignore this warning",
"choose_loglevel": "💁♂️ Choose log level",
}
@staticmethod
async def dumpcmd(message: Message) -> None:
"""Use in reply to get a dump of a message"""
if not message.is_reply:
return
await utils.answer(
message,
""
+ utils.escape_html((await message.get_reply_message()).stringify())
+ "
",
)
@staticmethod
async def cancel(call: aiogram.types.CallbackQuery) -> None:
await call.delete()
async def logscmd(
self,
message: Union[Message, aiogram.types.CallbackQuery],
force: bool = False,
lvl: Union[int, None] = None,
) -> None:
""" - Dumps logs. Loglevels below WARNING may contain personal info."""
if not isinstance(lvl, int):
args = utils.get_args_raw(message)
try:
try:
lvl = int(args.split()[0])
except ValueError:
lvl = getattr(logging, args.split()[0].upper(), None)
except IndexError:
lvl = None
if not isinstance(lvl, int):
if self.inline.init_complete:
await self.inline.form(
text=self.strings("choose_loglevel"),
reply_markup=[
[
{
"text": "🚨 Critical",
"callback": self.logscmd,
"args": (False, 50),
},
{
"text": "🚫 Error",
"callback": self.logscmd,
"args": (False, 40),
},
],
[
{
"text": "⚠️ Warning",
"callback": self.logscmd,
"args": (False, 30),
},
{
"text": "ℹ️ Info",
"callback": self.logscmd,
"args": (False, 20),
},
],
[
{
"text": "🧑💻 Debug",
"callback": self.logscmd,
"args": (False, 10),
},
{
"text": "👁 All",
"callback": self.logscmd,
"args": (False, 0),
},
],
[{"text": "🚫 Cancel", "callback": self.cancel}],
],
message=message,
)
else:
await utils.answer(message, self.strings("set_loglevel"))
return
logs = "\n\n".join(
[
("\n".join(handler.dumps(lvl)))
for handler in logging.getLogger().handlers
]
).encode("utf-16")
named_lvl = (
lvl if lvl not in logging._levelToName else logging._levelToName[lvl] # skipcq: PYL-W0212
)
if (
lvl < logging.WARNING
and not force
and (
not isinstance(message, Message)
or "force_insecure" not in message.raw_text.lower()
)
):
if self.inline.init_complete:
try:
cfg = {
"text": self.strings("confidential").format(named_lvl),
"reply_markup": [
[
{
"text": "📤 Send anyway",
"callback": self.logscmd,
"args": [True, lvl],
},
{"text": "🚫 Cancel", "callback": self.cancel},
]
],
}
if isinstance(message, Message):
await self.inline.form(**cfg, message=message)
else:
await message.edit(**cfg)
except ChatSendInlineForbiddenError:
await utils.answer(
message, self.strings("confidential_text").format(named_lvl)
)
else:
await utils.answer(
message, self.strings("confidential_text").format(named_lvl)
)
return
if len(logs) <= 2:
if isinstance(message, Message):
await utils.answer(message, self.strings("no_logs").format(named_lvl))
else:
await message.edit(self.strings("no_logs").format(named_lvl))
await message.unload()
return
logs = BytesIO(logs)
logs.name = self.strings("logs_filename")
other = (*main.__version__, utils.formatted_uptime(), utils.get_named_platform())
if isinstance(message, Message):
await message.delete()
await utils.answer(
message, logs, caption=self.strings("logs_caption").format(named_lvl, *other)
)
else:
await message.delete()
await self._client.send_file(
message.form["chat"],
logs,
caption=self.strings("logs_caption").format(named_lvl, *other),
)
@loader.owner
async def suspendcmd(self, message: Message) -> None:
"""