2.0 Да я ебал это все рассписывать но тут типо новая система логгирования

This commit is contained in:
Verum
2025-03-12 06:44:14 +07:00
parent 0704b2600f
commit 142753dc81
48 changed files with 634 additions and 239 deletions

View File

@@ -4,9 +4,6 @@
from aiogram import Router
from .routers import router as all_routers
from .inline import router as inline_routers
from .inline import *
from .keyboards import *
from .utils import *
# Объявление главного роутера
router = Router(name="main_router")

View File

@@ -0,0 +1,13 @@
# BotCode/easteggs/__init__.py
# Инициализация модуля easteggs, для создания пасхалок
from aiogram import Router
from .holidays import router as holiday_router
# Объявление роутера и настройка экспорта модулей
__all__ = ("router",)
router = Router(name="easteggs_router")
# Список подключаемых роутеров сверху-вниз
router.include_router(holiday_router)

View File

@@ -0,0 +1,21 @@
# BotCode/easteggs/holidays/__init__.py
# Инициализация модуля holidays, для пасхальных поздравлений
# Экспортирование модулей во внешние слои проекта
from aiogram import Router
from .march8 import *
# Объявление роутера и настройка экспорта модулей
__all__ = ("router",)
router = Router(name="holidays_router")
# Список подключаемых роутеров сверху-вниз
router.include_routers(
March8.router,
March8_Finaki.router,
March8_sleshik.router,
March8_polina.router,
March8_finik.router,
March8_kataz.router,
)

View File

@@ -0,0 +1,106 @@
# BotCode/easteggs/holidays/8March.py
# Работа с командой /march8, для вывода поздравления с 8 Марта!
from BotLibrary import CommandHandler
from BotCode.keyboards import get_march8_inline_kb, get_return_march8_inline_kb
# Настройки экспорта в модули
__all__ = ("March8", "March8_Finaki", "March8_finik", "March8_kataz", "March8_sleshik", "March8_polina")
march8_happy_text = ("""🌸 <b>С 8 Марта!</b> 🌸
Вы наши дорогие девушки, мы хотим поздравить вас в честь этого праздника!
Пусть этот день принесёт вам <i>море улыбок</i>, <i>приятные воспоминания</i> и <i>теплые слова</i>! 🌷
Пусть каждый день будет наполнен <b>радостью</b>, <b>счастьем</b> и <b>любовью</b>, а мечты сбываются <b>легко и красиво!</b> 💐
Оставайтесь такими же прекрасными, вдохновляющими и неповторимыми! ✨ С праздником! 💖
Вы и сами знаете, что нужно сделать. Тогда <i>Вперед за Истиной</i>, наши любимые!""")
finaki_text = ("""
Финаки, милая, поздравляем тебя с 8 Марта!🌸 Помни и старайся не забывать, о том, что все таки по настоящему важно.
Ты сильно повзрослела, за то время сколько мы знакомы и я рад видеть, как ты превращаешься из той мелкой балбески-финаки, во взрослую Аню.💪
Надеюсь, что ты все также будешь покорять вершины, а главное не будешь ничего бояться. С 8 Марта Финаки!✨
""")
lostic_text = ("""
Слешик-Лостик, сколько имен, но ты навсегда останешься для нас той самой малышкой, с которой мы прошли через огонь, воду и медные кафешки. 🌸
Желаем тебе только счастья, чтобы с каждым днем ты становилась всё более радостной и яркой. Пусть твои глаза никогда не наполняются слезами, а сердце всегда согревает любовь и счастье. ❤️
Слешик, с 8 Марта! Радуйся и дари радость всем вокруг, милаш! ✨ Ты заслуживаешь только самого лучшего, пусть каждый твой день будет наполнен теплом и светом!
""")
kataz_text = ("""
Катаз? А это кто? 😜
Хахах, мы шутим! Катаз, с 8 Марта! 🌸 Помним тебя такой мелкой, а теперь уже, смотри, мешки с песком совращаешь! 💪 Расти, развивайся, не забывай учиться и, главное, думай, ведь ты всегда была умницей, Катазик! 🤔
Пусть этот день принесет тебе море радости, а впереди будет только светлое будущее. Помни, что именно поэтому ты — Катазик! 🌟
С праздником, кактус! 🌵 С праздником! Пусть каждый день будет полон ярких моментов и вдохновения! 🎉
""")
finik_text = ("""
def main(): print("Ох, кажется, что-то не тому мы это пишем! Финик, малыш, с 8 Марта! 🌸 Многое изменилось, как и ты, но даже так, я безмерно рад, что знаком с таким удивительным нефоренком!🌟)
Расти, познавай мир и следуй за Истиной! То, что мы найдем с тобой - это место, место, в кототором мы впервые услышим твой смех, а не крики от ужастиков😂 Будь умницей,")
мы ведь тобой очень дорожим.❤️ С праздником, малыш!✨
""")
polina_text = ("""
Полина-Полина, с тобой мы знакомы меньше всего, но уже ты стала нам очень дорогим человеком и настоящей подругой. 🌸 Ты как цветок, что появился из пепла — как же он звался? Не важно… Главное, что ты, как этот цветок, продолжаешь расцветать, быть такой же уникальной и прекрасной, как нечто совершенно особенное, созданное из другой материи. 💫
С 8 Марта, балбеска! 😄 Пусть этот день будет полон радости и вдохновения! Мы всегда будем рады выслушать твои истории и, главное, поддержать тебя в любом начинании. Ты заслуживаешь только самого лучшего!
Будь умничкой, Поляк! 🌷
""")
# Создание команды /march8 с несколькими медиа
March8 = CommandHandler(
name="march8",
description="Поздравление с 8 Марта!",
keywords=["march8"],
keyboard=get_march8_inline_kb, delete_msg=True,
media="photo", path_to_media=["ProjectsFiles/media/Banners/march8_banner.jpeg"],
text_msg=march8_happy_text,
)
# Создание команды /march8_finaki
March8_Finaki = CommandHandler(
name="march8_finaki",
description="Поздравление с 8 Марта Финаки!",
keywords=["march8_finaki"],
keyboard=get_return_march8_inline_kb, delete_msg=True,
media="photo", path_to_media=["ProjectsFiles/media/Banners/march8_finaki_banner.jpeg"],
text_msg=finaki_text,
)
# Создание команды /march8_finik
March8_finik = CommandHandler(
name="march8_finik",
description="Поздравление с 8 Марта Финик!",
keywords=["march8_finik"],
keyboard=get_return_march8_inline_kb, delete_msg=True,
media="photo", path_to_media=["ProjectsFiles/media/Banners/march8_finik_banner.jpeg"],
text_msg=finik_text,
)
# Создание команды /march8_polina
March8_polina = CommandHandler(
name="march8_polina",
description="Поздравление с 8 Марта Полина!",
keywords=["march8_polina"],
keyboard=get_return_march8_inline_kb, delete_msg=True,
media="photo", path_to_media=["ProjectsFiles/media/Banners/march8_polina_banner.png"],
text_msg=polina_text,
)
# Создание команды /march8_kataz
March8_kataz = CommandHandler(
name="march8_kataz",
description="Поздравление с 8 Марта Катаз!",
keywords=["march8_kataz"],
keyboard=get_return_march8_inline_kb, delete_msg=True,
media="photo", path_to_media=["ProjectsFiles/media/Banners/march8_kataz_banner.png"],
text_msg=kataz_text,
)
# Создание команды /march8_sleshik
March8_sleshik = CommandHandler(
name="march8_sleshik",
description="Поздравление с 8 Марта Слешик!",
keywords=["march8_sleshik"],
keyboard=get_return_march8_inline_kb, delete_msg=True,
media="photo", path_to_media=["ProjectsFiles/media/Banners/march8_lostik_banner.png"],
text_msg=lostic_text,
)

View File

@@ -4,3 +4,4 @@
# Экспортирование модулей во внешние слои проекта
from .start_inline_kb import get_start_kb
from .my_inline_kb import get_my_inline_kb
from .march8_inline_kb import get_march8_inline_kb, get_return_march8_inline_kb

View File

@@ -0,0 +1,26 @@
# BotCode/keyboards/inline_kb/8march_inline_kb.py
# Создание инлайн-клавиатуры на команду: /march8
from BotLibrary import BaseInlineKeyboard
# Настройка экспорта в модули
__all__ = ("get_march8_inline_kb", "get_return_march8_inline_kb")
# Функция создания клавиатуры
def get_march8_inline_kb(row_width : int = 2):
buttons = [
("🍓Финаки", None, "march8_finaki"),
("🍬Финик", None, "march8_finik"),
("💋Поля", None, "march8_polina"),
("😈Катазик", None, "march8_kataz"),
("🪭Слешик", None, "march8_sleshik"),
]
return BaseInlineKeyboard(buttons, row_width=row_width).get_keyboard()
# Функция возвратной клавиатуры
def get_return_march8_inline_kb(row_width : int = 1):
buttons = [
("🥰Назад", None, "march8"),
]
return BaseInlineKeyboard(buttons, row_width=row_width).get_keyboard()

View File

@@ -15,7 +15,6 @@ all_cmd = CommandHandler(
name="all",
description="Всеобщий призыв",
keywords=["all", "фдд", "@all"],
callbackdata=["keywords"],
media="command",
func=[lambda message, *args: hidden_admins_message(message, msg=False, text=message.text.split(" ", 1)[1] if len(message.text.split(" ", 1)) > 1 else custom_text)],
)

View File

@@ -43,6 +43,5 @@ ban_cmd = CommandHandler(
name="ban",
description="Блокировка пользователя",
keywords=["ban", "бан", "banhammer", "ифтрфььук", "ифт"],
callbackdata=["keywords"],
media="command", func=[ban_user],
)

View File

@@ -5,6 +5,7 @@
from aiogram import Router
from .polina_anketa import polina_za_tri_eleksira_cmd
from .kataz_pidaraz_2020 import kataz_pidaraz_2020_cmd
from .finaki_succub import finaki_succub_cmd
# Объявление роутера и настройка экспорта модулей
__all__ = ("router",)
@@ -15,4 +16,5 @@ router = Router(name="easteggs_cmd_router")
router.include_routers(
polina_za_tri_eleksira_cmd.router,
kataz_pidaraz_2020_cmd.router,
finaki_succub_cmd.router,
)

View File

@@ -0,0 +1,43 @@
# BotCode/routers/commands/easteggs_cmd/finaki_succub.py
# Работа с командой /finaki_succub, для вывода анкеты
from BotLibrary import CommandHandler
from BotCode.keyboards import get_my_inline_kb
# Настройки экспорта в модули
__all__ = ("finaki_succub_cmd",)
# Шаблон анкеты
shablon_anketa = ("""📜 \\| **Статистика персонажа**
👤 **Пользователь:** [Е Лань: Цветок Орхидеи](https://t.me/fin_aki)
🏅 **Ранг:** Участник
🌀 **Раса:** Суккуб
📊 **Активность \\\\\\\|всего\):**
🗨 **День:** 69 \\| **Неделя:** 69 \\| **Месяц:** 69 \\| **Всего:** 69
🏠 **Группа:** Мемори\-IX \\| Заместитель
🧭 **Состояние персонажа**
❤️ **Здоровье:** ▰▰▰▰▰▰▰▱▱▱ \(70%\)
🍖 **Голод:** ▰▰▰▰▰▰▰▰▱▱ \(80%\)
🧠 **Рассудок:** ▰▰▰▰▰▰▱▱▱▱ \(60%\)
📌 **Важные события**
🏠 **Бункер:** Создание нового бункера в северных окрестностях города
🕵 **Разведка:** Нашла временную базу культистов "Мертвой души"
🎒 **Поиски:** Обнаружила картину Художника "Чужой \- муза культистов"
""")
# Создание команды /my с несколькими медиа
finaki_succub_cmd = CommandHandler(
name="finaki_succub",
description="Получение личной анкеты Финаки",
keywords=["finaki_succub"],
keyboard=get_my_inline_kb,
media="photo", path_to_media=["ProjectsFiles/media/Banners/finaki_my.jpeg"],
text_msg=shablon_anketa,
parse_mode="MarkdownV2",
)

View File

@@ -34,7 +34,7 @@ kataz_pidaraz_2020_cmd = CommandHandler(
name="kataz_pidaraz_2020",
description="Получение личной анкеты Катаза",
keywords=["kataz_pidaraz_2020"],
keyboard=get_my_inline_kb, callbackdata=["keywords"],
keyboard=get_my_inline_kb,
media="photo", path_to_media=["ProjectsFiles/media/Anketa/kataz_easteggs.jpeg"],
text_msg=shablon_anketa,
parse_mode="MarkdownV2",

View File

@@ -33,7 +33,7 @@ polina_za_tri_eleksira_cmd = CommandHandler(
name="polina_za_tri_eleksira",
description="Получение личной анкеты Поляка",
keywords=["polina_za_tri_eleksira"],
keyboard=get_my_inline_kb, callbackdata=["keywords"],
keyboard=get_my_inline_kb,
media="photo", path_to_media=["ProjectsFiles/media/Anketa/polina_easteggs_anketa.jpeg"],
text_msg=shablon_anketa,
parse_mode="MarkdownV2",

View File

@@ -12,6 +12,6 @@ help_cmd = CommandHandler(
name="help",
description="Получить помощь",
keywords=["help", "info", "помощь", "инфо", "информация", "рудз", "штащ", "byaj", "gjvjom", "byajhvfwbz"],
keyboard=get_help_kb, callbackdata=["keywords"],
keyboard=get_help_kb,
text_msg="Привет! Это команда помощи. Тут ты можешь узнать, как пользоваться ботом.",
)

View File

@@ -8,7 +8,7 @@ from BotCode.keyboards import get_my_inline_kb
__all__ = ("my_cmd",)
# Шаблон анкеты
shablon_anketa = """
shablon_anketa = ("""
📜 \\| **Статистика персонажа**
👤 **Пользователь:** [Альбедо](http://t.me/verdise)
@@ -27,15 +27,14 @@ shablon_anketa = """
📌 **Важные события**
🕵 **Разведка:** Обнаружена Лаборатория X\-18
💀 **Смерть:** Удушение
"""
""")
# Создание команды /my с несколькими медиа
my_cmd = CommandHandler(
name="my",
description="Получение личной анкеты",
keywords=["my", "ьн", "me", "ьу"],
keyboard=get_my_inline_kb, callbackdata=["keywords"],
keyboard=get_my_inline_kb,
media="photo", path_to_media=["ProjectsFiles/media/Anketa/albedo_anketa.png"],
text_msg=shablon_anketa,
parse_mode="MarkdownV2",

View File

@@ -12,7 +12,7 @@ start_cmd = CommandHandler(
name="start",
description="Добро пожаловать!",
keywords=["start", "старт", "cnfhn", "ыефке", "пуск", "gecr", "on"],
keyboard=get_start_kb, callbackdata=["keywords"],
keyboard=get_start_kb,
media="photo", path_to_media=["ProjectsFiles/media/Banners/start_banner.jpg",],
text_msg="Привет! Вот группа фото!",
)

View File

@@ -12,7 +12,6 @@ start_time_cmd = CommandHandler(
keywords=["start_time", "stime", "старт_время", "время_старта", "сремя",
"ыефке_ешьу", "ыешьу", "cnfhn_dhtvcz", "dhtvz_cnfhnf", "c_dhtvz",
"бот_время", "время_запуска", "бот_врем", "on_time", "щт_ешьу"],
callbackdata=["keywords"],
text_msg=lambda: f"Бот @{BotInfo.username} запущен: "
f"\nХост: <b>{dp['started_at']}</b> "
f"\nМСК: <b>{dp['started_at_msk']}</b>",

View File

@@ -31,6 +31,5 @@ stats_cmd = CommandHandler(
name="stats",
description="Вывод статистики о пользователи",
keywords=["stats", "ыефеы", "cnfnf", "стата", "Кто я", "Rnj z", "vjbcjj,otybz", "моисообщения"],
callbackdata=["keywords"],
media="command", func=[send_stats],
)

View File

@@ -10,7 +10,6 @@ weather_cmd = CommandHandler(
name="weather",
description="Погода",
keywords=["weather", "gjujlf", "цуферук", "погода"],
callbackdata=["keywords"],
media="command",
func=[get_weather],
)

View File

@@ -17,4 +17,4 @@ router = Router(name="common_msg_router")
async def handle_all_messages(message: types.Message):
await base_sql(message)
await status_user(message)
await logger_msg(message) # Это твой метод для логирования
Logs.msg(message)

View File

@@ -4,7 +4,38 @@
# Экспортирование модулей во внешние слои проекта
from .analytics import *
from .loggers import *
from .samples import *
from .system import *
from .timer import *
from .validators import *
from .samples import *
from SQLite3 import create_user_db
from ProjectsFiles import Permissions
# Функция установки
async def setup():
# Запуск логеров
await setup_logger()
# Получение информации о боте
await bot_get_info()
# Вывод сообщение о запуске
Logs.start(text=f"Начало запуска бота @{BotInfo.username}...")
Logs.console()
# Автоматическое создание базы данных при отсутствии
await create_user_db()
# Создание пустых директорий
await setup_directories()
# Нужно ли удалить веб-хук
if Permissions.delete_webhook:
await bot.delete_webhook()
await set_adm_rights()
await set_bot_name()
await set_bot_description()
await set_bot_short_description()

View File

@@ -1,10 +1,13 @@
# BotLibrary/analytics/type_msg.py
# Проверяет тип сообщения
from aiogram.types import ContentType, Message
# Настройка экспорта из модуля
__all__ = ("types_message",)
__all__ = ("type_msg",)
# Функция определения типа сообщения
def types_message(message: Message) -> str:
def type_msg(message: Message) -> str:
"""
Функция для определения типа сообщения на основе его содержимого.
@@ -68,7 +71,7 @@ def types_message(message: Message) -> str:
ContentType.GROUP_CHAT_CREATED: "Создание группового чата",
ContentType.SUPERGROUP_CHAT_CREATED: "Создание супергруппы",
ContentType.CHANNEL_CHAT_CREATED: "Создание канала",
ContentType.MESSAGE_AUTO_DELETE_TIMER_CHANGED: "Изменение таймера автоудаления сообщения",
ContentType.MESSAGE_AUTO_DELETE_TIMER_CHANGED: "Изменение таймера авто-удаления сообщения",
}
# Получение типа сообщения

View File

@@ -1,8 +1,6 @@
# BotLibrary/loggers/__init__.py
# Инициализация пакета loggers, для создания логеров
# Инициализация под-пакета loggers, для настройки логеров
# Экспортирование модулей во внешние слои проекта
from .logs import *
from .msg_logger import *
from .custom_loggers import *
from .start_info_out import *

View File

@@ -1,10 +1,17 @@
# BotLibrary/loggers/custom_loggers.py
# Кастомные логгеры для проекта, с более стандартизированным использованием
from time import sleep
from colorama import Fore
from loguru import logger
from ..validators import username
from aiogram.types import Message
from BotLibrary.system.bots import BotInfo
from BotLibrary.validators.username import username
from BotLibrary.analytics.type_msg import type_msg
from ProjectsFiles import BotLogs, Permissions, ProjectPath, BotVar, bot_owner
# Настройка экспорта из модуля
__all__ = ("Logs",)
@@ -13,8 +20,10 @@ class Logs:
"""Класс для логирования с разными уровнями через loguru."""
@staticmethod
def start(text: str = "Логирование!", system: str = "PRIMO",
log_type: str = "AEP", user: str = "@Console") -> None:
def start(text: str = "Логирование!",
system: str = "PRIMO",
log_type: str = "AEP",
user: str = "@Console") -> None:
"""
Логирует сообщение на уровне DEBUG.
@@ -22,12 +31,18 @@ class Logs:
:param text: Сообщение для логирования.
:param log_type: Тип лога (например, "Logs").
:param user: Имя пользователя или источник вызова лога.
:return: Вывод сообщения об старте бота
"""
logger.bind(system=system, user=user, log_type=log_type).log("START", text)
@staticmethod
def debug(text: str = "Логирование!", system : str = "DEBUG",
log_type: str = "Logs", user: str = "@Console", message: Message = None) -> None:
def debug(text: str = "Логирование!",
system: str = "DEBUG",
log_type: str = "Logs",
user: str = "@Console",
message: Message = None) -> None:
"""
Логирует сообщение на уровне DEBUG.
@@ -36,14 +51,20 @@ class Logs:
:param log_type: Тип лога (например, "Logs").
:param user: Имя пользователя или источник вызова лога.
:param message: Сообщение от пользователя, если необходимо извлечь имя.
:return: Вывод сообщения об дебаг-информации
"""
if message:
user = username(message)
logger.bind(system=system, log_type=log_type, user=user).debug(text)
@staticmethod
def info(text: str = "Логирование!", system : str = "PRIMO",
log_type: str = "Logs", user: str = "@Console", message: Message = None) -> None:
def info(text: str = "Логирование!",
system: str = "PRIMO",
log_type: str = "Logs",
user: str = "@Console",
message: Message = None) -> None:
"""
Логирует сообщение на уровне INFO.
@@ -52,14 +73,20 @@ class Logs:
:param log_type: Тип лога (например, "Logs").
:param user: Имя пользователя или источник вызова лога.
:param message: Сообщение от пользователя, если необходимо извлечь имя.
:return: Вывод сообщения об некой информации
"""
if message:
user = username(message)
logger.bind(system=system, log_type=log_type, user=user).info(text)
@staticmethod
def warning(text: str = "Логирование!", system : str = "WARNING",
log_type: str = "Logs", user: str = "@Console", message: Message = None) -> None:
def warning(text: str = "Логирование!",
system: str = "WARNING",
log_type: str = "Logs",
user: str = "@Console",
message: Message = None) -> None:
"""
Логирует сообщение на уровне WARNING.
@@ -68,14 +95,20 @@ class Logs:
:param log_type: Тип лога (например, "Logs").
:param user: Имя пользователя или источник вызова лога.
:param message: Сообщение от пользователя, если необходимо извлечь имя.
:return: Вывод сообщения об предупреждении
"""
if message:
user = username(message)
logger.bind(system=system, log_type=log_type, user=user).warning(text)
@staticmethod
def error(text: str = "Логирование!", system : str = "ERROR",
log_type: str = "Logs", user: str = "@Console", message: Message = None) -> None:
def error(text: str = "Логирование!",
system: str = "ERROR",
log_type: str = "Logs",
user: str = "@Console",
message: Message = None) -> None:
"""
Логирует сообщение на уровне ERROR.
@@ -84,7 +117,80 @@ class Logs:
:param log_type: Тип лога (например, "Logs").
:param user: Имя пользователя или источник вызова лога.
:param message: Сообщение от пользователя, если необходимо извлечь имя.
:return: Вывод сообщения об ошибке
"""
if message:
user = username(message)
logger.bind(system=system, log_type=log_type, user=user).error(text)
@staticmethod
def msg(message: Message,
log_type: str = "Message",
permission: bool = BotLogs.permission) -> None:
"""
Логирует сообщение, если оно не обработано.
:param message: Сообщение от пользователя
:param log_type: Тип лога (по умолчанию "Message")
:param permission: Разрешение на логирование (config)
:return: Вывод сообщения об обычном сообщении пользователя
"""
# Получаем username или id пользователя
user: str = f"@{message.from_user.username or message.from_user.id}"
msg_type: str = type_msg(message)
# Логирование только если разрешено
if permission:
# Проверка на наличие текста и его типа
if message.text is None and msg_type not in ("Новые участники чата", "Ушедший участник чата"):
Logs.info(log_type=log_type, user=user, text=f"Получено сообщение из ({message.chat.id}) : {msg_type}")
elif message.text is not None:
Logs.info(log_type=log_type, user=user,
text=f"Получено сообщение из ({message.chat.id}) : {message.text}")
@staticmethod
def console(stop_time: int = 1,
console: bool = Permissions.start_info_console,
file: bool = Permissions.start_info_to_file,
path: str = ProjectPath.bot_info_log_file,) -> None:
"""
Собирает информацию о боте и выводит её в консоль, а также возвращает как строку.
:param stop_time: Количество времени в секундах, после которых выведется информация (1 сек)
:param console: Разрешение на внесение информации в консоль (config)
:param file: Разрешение на внесение информации в файл (config)
:param path: Путь до файла для сохранения информации о боте (config)
:return: Информация о боте в виде строки.
"""
# Собираем данные о боте
bot_name: str = f"Основное имя: {BotInfo.first_name}\n"
bot_post_name: str = f"Владельцы бота: {bot_owner}\n"
bot_username: str = f"Юзернейм: @{BotInfo.username}\n"
bot_id: str = f"ID: {BotInfo.id}\n"
bot_can_join_groups: str = f"Может ли вступать в группы: {BotInfo.can_join_groups}\n"
bot_can_read_all_group_messages: str = f"Чтение всех сообщений: {BotInfo.can_read_all_group_messages}\n"
bot_supports_inline_queries: str = f"Поддерживает инлайн-запросы: {BotInfo.supports_inline_queries}\n"
bot_can_connect_to_business: str = f"Подключение к бизнес-аккаунтам: {BotInfo.can_connect_to_business}\n"
bot_has_main_web_app: str = f"Основное веб-приложение: {BotInfo.has_main_web_app}\n"
# Формируем полный текст с выводом информации о боте
bot_all_info: str = (f"{bot_name} {bot_post_name} {bot_username} {bot_id} "
f"{bot_can_join_groups} {bot_can_read_all_group_messages} "
f"{bot_supports_inline_queries} {bot_can_connect_to_business} "
f"{bot_has_main_web_app}")
# Печатаем всю информацию в консоль с задержкой
if console:
sleep(stop_time)
print(Fore.CYAN + bot_all_info)
# Печатаем всю информацию в файл
if file:
# Преобразуем словарь bot_all_info в строку и записываем в файл
with open(path, 'w', encoding=BotVar.encod) as file:
file.write(str(bot_all_info))

View File

@@ -1,33 +1,45 @@
# BotLibrary/system/logs.py
# BotLibrary/loggers/logs.py
# Создание логгеров и их шаблон для проекта
import sys
from loguru import logger
from ProjectsFiles import BotLogs, ProjectPath
# Настройка экспорта из модуля
__all__ = ("setup_logger",)
# Создание обычного логгера + логгер в файл
async def setup_logger() -> None:
async def setup_logger(logging: bool = BotLogs.permission,
to_file: bool = BotLogs.permission_to_file) -> None:
"""
Настройка логгеров для проекта, выводящих логи в консоль.
Логгеры конфигурируются в зависимости от настроек в BotLogs.
Настройка логгеров для проекта, выводящих логи в консоль и файлы.
Логгеры конфигурируются в зависимости от настроек в конфигах проекта.
Если разрешено логирование, добавляются логи для уровней DEBUG, INFO, WARNING, ERROR.
"""
logger.remove() # Удаляем все логгеры
И кастомные такие, как START, NEW_USER, LEAVE_USER
if BotLogs.permission and BotLogs.permission_to_file:
:param logging: Разрешение на логирование в консоль (config)
:param to_file: Разрешение на логирование в файл (config)
:return: Создание логеров под различные уровни
"""
logger.remove() # Удаляем все стандартные логгеры
# Если есть разрешение, то он создает новые уровни
if logging and BotLogs.permission_to_file:
# Добавляем новый уровень START
logger.level("START", no=25, color="white", icon="🔸")
if BotLogs.permission and BotLogs.permission_new_user:
if logging and BotLogs.permission_new_user:
# Добавляем новый уровень NEW_USER
logger.level("NEW_USER", no=4, color="white", icon="👋")
if BotLogs.permission and BotLogs.permission_leave_user:
if logging and BotLogs.permission_leave_user:
# Добавляем новый уровень LEAVE_USER
logger.level("LEAVE_USER", no=3, color="white", icon="🫰")
# Настройка логирования в консоль для каждого уровня
if BotLogs.permission:
if logging:
logger.add(sys.stderr,
colorize=True,
format=BotLogs.start_text,
@@ -55,8 +67,9 @@ async def setup_logger() -> None:
level="ERROR",
filter=lambda record: record["level"].name == "ERROR")
# Добавление логгера для записи в файл
if BotLogs.permission_to_file:
if to_file:
logger.add(ProjectPath.start_log_file,
rotation=BotLogs.max_size,
format=BotLogs.start_text,

View File

@@ -1,32 +0,0 @@
# BotLibrary/loggers/msg_logger.py
# Логгер для всех не обработанных сообщений
from ProjectsFiles import BotLogs
from .custom_loggers import Logs
from ..analytics.type_msg import types_message
from aiogram.types import Message
# Настройка экспорта из модуля
__all__ = ("logger_msg",)
# Создание функции логирования на обычные сообщения
async def logger_msg(message: Message, log_type: str = "Message") -> None:
"""
Логирует сообщение, если оно не обработано.
:param message: Сообщение от пользователя.
:param log_type: Тип лога (по умолчанию "Message").
"""
# Получаем username или id пользователя
user: str = f"@{message.from_user.username or message.from_user.id}"
msg_type = types_message(message)
# Логирование только если разрешено
if BotLogs.permission:
# Проверка на наличие текста и его типа
if message.text is None and msg_type not in ("Новые участники чата", "Ушедший участник чата"):
Logs.info(log_type=log_type, user=user, text=f"Получено сообщение из ({message.chat.id}) : {msg_type}")
elif message.text is not None:
Logs.info(log_type=log_type, user=user, text=f"Получено сообщение из ({message.chat.id}) : {message.text}")
else:
return

View File

@@ -1,48 +0,0 @@
# BotLibrary/loggers/start_info_out.py
# Вывод данных бота в консоль для начальной проверки
from time import sleep
from colorama import Fore
from ProjectsFiles import Permissions, ProjectPath, BotVar, bot_owner
from .custom_loggers import Logs
from ..system import BotInfo
# Функция для получения информации о боте и выводе ее в консоль и файл
def bot_info_out() -> str:
"""
Собирает информацию о боте и выводит её в консоль, а также возвращает как строку.
:return: Информация о боте в виде строки.
"""
try:
# Собираем данные о боте
bot_name: str = f"Основное имя: {BotInfo.first_name}\n"
bot_post_name: str = f"Владельцы бота: {bot_owner}\n"
bot_username: str = f"Юзернейм: @{BotInfo.username}\n"
bot_id: str = f"ID: {BotInfo.id}\n"
bot_can_join_groups: str = f"Может ли вступать в группы: {BotInfo.can_join_groups}\n"
bot_can_read_all_group_messages: str = f"Чтение всех сообщений: {BotInfo.can_read_all_group_messages}\n"
bot_supports_inline_queries: str = f"Поддерживает инлайн-запросы: {BotInfo.supports_inline_queries}\n"
bot_can_connect_to_business: str = f"Подключение к бизнес-аккаунтам: {BotInfo.can_connect_to_business}\n"
bot_has_main_web_app: str = f"Основное веб-приложение: {BotInfo.has_main_web_app}\n"
# Формируем полный текст с выводом информации о боте
bot_all_info: str = (f"{bot_name} {bot_post_name} {bot_username} {bot_id} "
f"{bot_can_join_groups} {bot_can_read_all_group_messages} "
f"{bot_supports_inline_queries} {bot_can_connect_to_business} "
f"{bot_has_main_web_app}")
# Печатаем все данные в консоль с задержкой в 1 секунду
sleep(1)
if Permissions.start_info_console:
print(Fore.CYAN + bot_all_info)
if Permissions.start_info_to_file:
# Преобразуем словарь bot_all_info в строку и записываем в файл
with open(ProjectPath.bot_info_log_file, 'w', encoding=BotVar.encod) as file:
file.write(str(bot_all_info))
return bot_all_info
except Exception as e:
Logs.error(log_type="SYS", user="Start_INFO", text=f"Ошибка при получении ID пользователя: {e}")

View File

@@ -1,3 +1,6 @@
# BotLibrary/samples/inline_kb_sample.py
# Шаблон для создания инлайн клавиатур
from aiogram.types import InlineKeyboardMarkup, ReplyKeyboardRemove
from aiogram.utils.keyboard import InlineKeyboardBuilder
from typing import List, Tuple, Optional

View File

@@ -1,5 +1,5 @@
# BotCode/keyboards/reply_kb/base_reply_kb.py
# Базовый класс для создания reply-клавиатур с расширенными возможностями и поддержкой row_width
# Базовый класс для создания reply-клавиатур
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, KeyboardButtonPollType, WebAppInfo, KeyboardButtonRequestUsers, KeyboardButtonRequestChat, KeyboardButtonRequestUser
from aiogram.utils.keyboard import ReplyKeyboardBuilder

View File

@@ -8,7 +8,8 @@ from aiogram.filters import Command
from aiogram.types import InputMediaPhoto, InputMediaVideo, InputMediaDocument
from typing import Optional, Callable
from BotLibrary import Logs, valid_url, username
from ..loggers import Logs
from ..validators import username, valid_url
from ProjectsFiles import BotVar
from SQLite3 import base_sql
@@ -19,7 +20,7 @@ class CommandHandler:
def __init__(self, name: str, keywords: list, func: Optional[list[Callable]] = None, text_msg=None, chat_action: bool = False,
description: str = "Описание команды", tg_links: bool = False,
keyboard=None, prefix=BotVar.prefix, callbackdata: list = None, only_admin: bool = False,
ignore_case: bool = True, activate_keywoards: bool = True,
ignore_case: bool = True, activate_keywords: bool = True, delete_msg: bool = False,
activate_commands: bool = True, activate_callback: bool = True,
media: str = "message", path_to_media=None, parse_mode: str = BotVar.parse_mode,
disable_notification: bool = BotVar.disable_notification, protect: bool = BotVar.protect_content):
@@ -27,6 +28,7 @@ class CommandHandler:
self.name = name
self.log_type = name.capitalize()
self.description = description
self.last_bot_message = {} # {chat_id: message_id}
self.keywords = keywords
self.text_msg = text_msg
@@ -39,6 +41,7 @@ class CommandHandler:
self.protect = protect
self.only_admin = only_admin
self.func = func
self.delete_msg = delete_msg
# Поддержка до 10 медиафайлов через список
if path_to_media is None:
@@ -49,25 +52,30 @@ class CommandHandler:
self.path_to_media = path_to_media[:10] # Ограничение до 10 элементов
self.tg_links = tg_links
if callbackdata == "keywords":
self.callbackdata = keywords
else:
if callbackdata:
self.callbackdata = callbackdata
else:
self.callbackdata = keywords
# Привязываем хэндлер к роутеру
if activate_commands:
self.router.message(Command(*keywords, prefix=prefix, ignore_case=ignore_case))(self.handler)
if activate_keywoards:
if activate_keywords:
self.router.message(F.text.lower().in_(keywords))(self.handler)
if activate_callback and self.callbackdata:
self.router.message(F.text.lower().in_(self.callbackdata))(self.handler)
self.router.callback_query(F.data.in_(self.callbackdata))(self.callback_handler)
async def callback_handler(self, callback: types.CallbackQuery):
"""Обработчик callback-запросов."""
await self.handler(callback.message) # Передаем сообщение в основном обработчике
await callback.answer() # Закрываем callback-запрос
async def handler(self, message: types.Message):
"""Основной хэндлер команды."""
try:
# Извлекаем текст после команды
command_text = message.text[len(message.text.split()[0]):].strip() # Убираем команду из текста
args = command_text.split() # Разделяем команду на аргументы
command_text = (message.text or "").strip() # Защита от NoneType
args = command_text.split() if command_text else [] # Если текст есть — разделяем, иначе пустой список
# Проверка на выполнение дополнительной функции (если она есть)
if self.func: # Проверяем, что функция не None
@@ -115,14 +123,16 @@ class CommandHandler:
if self.tg_links:
text = text.replace("<users>", str(message.from_user.id))
sent_msg = None
if self.media == "message":
await message.reply(
sent_msg = await message.reply(
text=text,
reply_markup=self.keyboard() if self.keyboard else None,
parse_mode=self.parse_mode,
disable_notification=self.disable_notification,
protect_content=self.protect,
)
self.last_bot_message[message.chat.id] = sent_msg.message_id
if self.chat_action:
await message.bot.send_chat_action(
chat_id=message.chat.id,
@@ -142,7 +152,7 @@ class CommandHandler:
media_group[-1].caption = text
media_group[-1].parse_mode = self.parse_mode
await message.reply_media_group(
sent_msg = await message.reply_media_group(
media=media_group,
disable_notification=self.disable_notification,
protect_content=self.protect,
@@ -173,7 +183,7 @@ class CommandHandler:
media_group[-1].caption = text
media_group[-1].parse_mode = self.parse_mode
await message.reply_media_group(
sent_msg = await message.reply_media_group(
media=media_group,
disable_notification=self.disable_notification,
protect_content=self.protect,
@@ -204,7 +214,7 @@ class CommandHandler:
media_group[-1].caption = text
media_group[-1].parse_mode = self.parse_mode
await message.reply_media_group(
sent_msg = await message.reply_media_group(
media=media_group,
disable_notification=self.disable_notification,
protect_content=self.protect,
@@ -229,7 +239,7 @@ class CommandHandler:
if self.media == "photo":
if url:
await message.reply_photo(
sent_msg = await message.reply_photo(
photo=media_path,
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -238,7 +248,7 @@ class CommandHandler:
protect_content=self.protect,
)
else:
await message.reply_photo(
sent_msg = await message.reply_photo(
photo=types.FSInputFile(path=media_path),
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -254,7 +264,7 @@ class CommandHandler:
elif self.media == "gif":
if url:
await message.reply_animation(
sent_msg = await message.reply_animation(
animation=media_path,
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -263,7 +273,7 @@ class CommandHandler:
protect_content=self.protect,
)
else:
await message.reply_animation(
sent_msg = await message.reply_animation(
animation=types.FSInputFile(path=media_path),
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -279,7 +289,7 @@ class CommandHandler:
elif self.media == "video":
if url:
await message.reply_video(
sent_msg = await message.reply_video(
video=media_path,
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -288,7 +298,7 @@ class CommandHandler:
protect_content=self.protect,
)
else:
await message.reply_video(
sent_msg = await message.reply_video(
video=types.FSInputFile(path=media_path),
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -304,7 +314,7 @@ class CommandHandler:
elif self.media == "videonote":
if url:
await message.reply_video_note(
sent_msg = await message.reply_video_note(
video_note=media_path,
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -313,7 +323,7 @@ class CommandHandler:
protect_content=self.protect,
)
else:
await message.reply_video_note(
sent_msg = await message.reply_video_note(
video_note=types.FSInputFile(path=media_path),
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -329,7 +339,7 @@ class CommandHandler:
elif self.media == "audio":
if url:
await message.reply_audio(
sent_msg = await message.reply_audio(
audio=media_path,
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -338,7 +348,7 @@ class CommandHandler:
protect_content=self.protect,
)
else:
await message.reply_audio(
sent_msg = await message.reply_audio(
audio=types.FSInputFile(path=media_path),
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -354,7 +364,7 @@ class CommandHandler:
elif self.media == "file":
if url:
await message.reply_document(
sent_msg = await message.reply_document(
document=media_path,
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -363,7 +373,7 @@ class CommandHandler:
protect_content=self.protect,
)
else:
await message.reply_document(
sent_msg = await message.reply_document(
document=types.FSInputFile(path=media_path),
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -378,7 +388,7 @@ class CommandHandler:
)
elif self.media == "dice":
await message.reply_dice(
sent_msg = await message.reply_dice(
emoji="🎲", # Эмодзи кубика как стандартное значение, если нет URL
caption=text if is_last else None,
reply_markup=self.keyboard() if is_last and self.keyboard else None,
@@ -392,6 +402,16 @@ class CommandHandler:
action=ChatAction.CHOOSE_STICKER,
)
# Сохраняем идентификатор последнего сообщения, если необходимо
if sent_msg:
self.last_bot_message[message.chat.id] = sent_msg.message_id
if self.delete_msg:
await message.bot.delete_message(
chat_id=message.chat.id,
message_id=message.message_id
)
# Проверка на ошибку
except Exception as e:
Logs.error(log_type=self.log_type, user=username(message), text=f"Ошибка команды: {e}")

View File

@@ -1,33 +1,22 @@
# BotLibrary/system/edit_bot.py
# Библиотека установки настроек бота через проект и конфиги
# BotLibrary/system/bot_edit.py
# Под-пакет установки настроек бота
from aiogram.types import ChatAdministratorRights
from ProjectsFiles import BotEdit
from .bots import bot
from ..loggers import Logs
# Настройка логирования
log_type = "Edit"
# Функция для выполнения всех настроек, если они не совпадают
async def set_all() -> None:
"""
Выполняет все необходимые настройки бота, если они не совпадают с текущими значениями.
:return: None
"""
await set_adm_rights()
await set_bot_name()
await set_bot_description()
await set_bot_short_description()
# Настройка экспорта из модуля
__all__ = ("set_adm_rights", "set_bot_name", "set_bot_description", "set_bot_short_description")
# Функция установки прав администратора
async def set_adm_rights() -> None:
"""
Устанавливает права администратора для бота, если они отличаются от текущих.
:return: None
:return: Изменение прав администратора
"""
rights = ChatAdministratorRights(
is_anonymous=BotEdit.is_anonymous,
@@ -54,57 +43,72 @@ async def set_adm_rights() -> None:
# Функция установки имени бота с проверкой на ограничения
async def set_bot_name() -> None:
async def set_bot_name(new_name: str = BotEdit.name) -> None:
"""
Устанавливает имя бота, если оно отличается от текущего и соответствует ограничениям.
:return: None
:param new_name: Новое имя бота (config)
:return: Имя бота
"""
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
from ..loggers.custom_loggers import Logs
# Получаем текущее имя бота
current_name = (await bot.get_me()).first_name
# Проверка длины имени
if len(BotEdit.name) < 1 or len(BotEdit.name) > 32:
if len(new_name) < 1 or len(new_name) > 32:
Logs.error(log_type=log_type, user="NAME_BOT", text="Имя бота должно быть от 1 до 32 символов.")
return # Выходим из функции, если имя некорректно
# Проверяем, совпадает ли текущее имя с тем, которое мы хотим установить
if current_name != BotEdit.name:
await bot.set_my_name(BotEdit.name)
if current_name != new_name:
await bot.set_my_name(new_name)
# Функция установки описания бота с проверкой на ограничения
async def set_bot_description() -> None:
async def set_bot_description(new_description: str = BotEdit.description) -> None:
"""
Устанавливает описание бота, если оно отличается от текущего и соответствует ограничениям.
:return: None
:param new_description: Новое описание для бота (config)
:return: Описание бота
"""
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
from ..loggers.custom_loggers import Logs
# Получаем текущее описание бота
current_description = await bot.get_my_description()
# Проверка длины описания
if len(BotEdit.description) > 255:
Logs.error(log_type=log_type, user="DISCRIPT", text="Короткое описание бота не может превышать 255 символов.")
if len(new_description) > 255 or len(new_description)==0:
Logs.error(log_type=log_type, user="DISCRIPT", text="Короткое описание бота не может превышать 255 символов или быть равно 0.")
return # Выходим из функции, если описание некорректно
# Проверяем, совпадает ли текущее описание с тем, которое мы хотим установить
if current_description != BotEdit.description:
await bot.set_my_description(description=BotEdit.description)
if current_description != new_description:
await bot.set_my_description(description=new_description)
# Функция установки короткого описания бота с проверкой на ограничения
async def set_bot_short_description() -> None:
async def set_bot_short_description(new_short_description: str = BotEdit.short_description) -> None:
"""
Устанавливает короткое описание бота, если оно отличается от текущего и соответствует ограничениям.
:return: None
:param new_short_description: Новое описание виджета для бота (config)
:return: Короткое описание бота
"""
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
from ..loggers.custom_loggers import Logs
# Получаем текущее короткое описание бота
current_short_description = await bot.get_my_short_description()
# Проверка длины короткого описания
if len(BotEdit.short_description) > 512:
Logs.error(log_type=log_type, user="SHORT_DISCRIPT", text="Описание виджета не может превышать 512 символов.")
if len(new_short_description) > 512 or len(new_short_description) == 0:
Logs.error(log_type=log_type, user="SHORT_DISCRIPT", text="Описание виджета не может превышать 512 символов или быть равно 0.")
return # Выходим из функции, если короткое описание некорректно
# Проверяем, совпадает ли текущее короткое описание с тем, которое мы хотим установить
if current_short_description != BotEdit.short_description:
await bot.set_my_short_description(short_description=BotEdit.short_description)
if current_short_description != new_short_description:
await bot.set_my_short_description(short_description=new_short_description)

View File

@@ -5,7 +5,7 @@ from aiogram import Dispatcher, Bot, F
from aiogram.client.default import DefaultBotProperties
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
from ..timer import get_host_time, get_moscow_time
from ..timer import get_host_time, get_city_time
from ProjectsFiles import bot_token, BotVar
@@ -16,7 +16,7 @@ ikb = InlineKeyboardBuilder()
# Настройка параметров диспатчера
dp = Dispatcher()
dp["started_at"] = get_host_time()
dp["started_at_msk"] = get_moscow_time()
dp["started_at_msk"] = get_city_time()
dp["is_active"] = True # Флаг активности бота
dp["logs"] = []
dp["users"] = {}

View File

@@ -7,31 +7,33 @@ from tzlocal import get_localzone
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from ProjectsFiles import BotVar
# Настройка экспорта из этого модуля
__all__ = ("scheduler", "get_city_time", "get_host_time")
# Создание планировщика для работы с задачами по времени
scheduler = AsyncIOScheduler(timezone=get_localzone().key)
def get_moscow_time() -> str:
# Функция получение иного времени
def get_city_time(city: str = 'Europe/Moscow') -> str:
"""
Получение текущего времени по московскому времени.
Получение текущего времени по иному городскому времени.
:param city: Город, что будет вторым временем
:return: Строка, представляющая время в формате, заданном в BotVar.time_format.
"""
# Устанавливаем временную зону для Москвы
moscow_tz = pytz.timezone('Europe/Moscow')
# Получаем текущее время по московскому времени
moscow_time = datetime.now(moscow_tz)
city_tz = pytz.timezone(city)
# Возвращаем строку с форматом времени
return moscow_time.strftime(BotVar.time_format)
return datetime.now(city_tz).strftime(BotVar.time_format)
# Функция получение времени хоста
def get_host_time() -> str:
"""
Получение текущего времени хоста (локального времени).
:return: Строка, представляющая локальное время в формате, заданном в BotVar.time_format.
"""
# Получаем текущее время на хосте
host_time = datetime.now()
# Возвращаем строку с форматом времени
return host_time.strftime(BotVar.time_format)
return datetime.now().strftime(BotVar.time_format)

View File

@@ -1,24 +1,25 @@
# BotLibrary/validators/email_validators.py
# Создание валидации почты для проекта
from email_validator import validate_email, EmailNotValidError
from typing import Optional
from email_validator import validate_email, EmailNotValidError
# Настройка экспорта из этого модуля
__all__ = ("valid_email",)
# Функция проверки почты на корректность
def valid_email(text: str) -> Optional[str]:
"""
Проверяет корректность почтового адреса.
:param text: Почтовый адрес в виде строки.
# Функция проверки почты на корректность
def valid_email(email: str) -> Optional[str]:
"""
Делает почтовый адрес корректным.
:param email: Почтовый адрес в виде строки.
:return: Нормализованный почтовый адрес, если он валиден, иначе None.
"""
try:
# Проверка и нормализация email
email = validate_email(text)
return email.normalized
except EmailNotValidError:
# Если email невалиден, можно добавить логирование или обработку ошибок
return validate_email(email).normalized
except EmailNotValidError as e:
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
from ..loggers.custom_loggers import Logs
Logs.error(text=f"Ошибка в нормализировании почты: {e}", log_type="NormalEmail")
return None

View File

@@ -1,5 +1,20 @@
# BotLibrary/validators/normal_word.py
# Нормализирует вид слова автоматически
async def normal_words(word : str = "Тестовое слово") -> str:
# Настройка экспорта из этого модуля
__all__ = ("normal_words",)
async def normal_words(word: str) -> str:
"""
Делает слово корректного вида.
:param word: Слово, которое будет приводиться к виду (Тесты).
:return: Нормализованное слово
"""
try:
return word.lower().capitalize()
except Exception as e:
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
from ..loggers.custom_loggers import Logs
Logs.error(text=f"Ошибка в нормализировании слова: {e}", log_type="NormalWord")
return word

View File

@@ -25,5 +25,27 @@ def valid_url(url: str) -> bool:
# Функция, что дает тексту ссылку на HTML
def url_to_text(text: str = "Тест", url: str = "www.google.com") -> str:
def url_to_text(text: str, url: str) -> str:
"""
Преобразует текст в HTML ссылку с указанным URL.
Эта функция генерирует HTML-ссылку с переданным текстом и URL, используя тег `<а>`, и делает ссылку жирной.
:param text: Текст, который будет отображаться для ссылки.
:param url: URL, который будет привязан к тексту.
:return: Строка с HTML кодом для ссылки, если URL валиден.
:raises ValueError: Если URL невалиден.
"""
try:
if not valid_url(url): # Проверяем, является ли URL валидным
raise ValueError(f"Переданный URL '{url}' невалиден.")
# Генерация HTML-ссылки
return f'<b><a href="{url}">{text}</a></b>'
except ValueError as e:
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
from ..loggers.custom_loggers import Logs
# Логируем ошибку с использованием Logs.error, как указано
Logs.error(text=f"Ошибка при создании ссылки: {e}", log_type="InvalidURL")
raise e # Перебрасываем ошибку выше для дальнейшей обработки или уведомления

View File

@@ -6,6 +6,7 @@ from aiogram.types import Message
# Настройка экспорта из модуля
__all__ = ("username", "username_to_text")
# Функция получения юзера или ID пользователя
def username(message: Message) -> str:
"""
@@ -13,12 +14,32 @@ def username(message: Message) -> str:
:param message: Объект сообщения из aiogram.
:return: Строка с юзернеймом пользователя или его ID.
:raises ValueError: Если в сообщении отсутствует информация о пользователе.
"""
try:
if message.from_user:
return f"@{message.from_user.username}" if message.from_user.username else f"@{message.from_user.id}"
return "@Unknown_User" # Если from_user отсутствует
raise ValueError("Информация о пользователе отсутствует в сообщении.")
except ValueError as e:
# Логируем ошибку с использованием Logs.error
raise e # Перебрасываем ошибку выше для дальнейшей обработки
# Функция получение имени пользователя + ссылка на него
def username_to_text(message: Message) -> str:
"""
Преобразует информацию о пользователе в строку с HTML-ссылкой.
:param message: Объект сообщения из aiogram.
:return: Строка с HTML-кодом для ссылки на пользователя.
:raises ValueError: Если в сообщении отсутствует информация о пользователе.
"""
try:
if message.from_user:
return f'<b><a href="tg://user?id={message.from_user.id}">{message.from_user.full_name}</a></b>'
raise ValueError("Информация о пользователе отсутствует в сообщении.")
except ValueError as e:
# Логируем ошибку с использованием Logs.error
raise e # Перебрасываем ошибку выше для дальнейшей обработки

49
Documentation/docs.md Normal file
View File

@@ -0,0 +1,49 @@
Начнем пожалуй с BotLibrary, я думаю после преобразовать его в пакет для ботов
Первый модуль analytics V
type_chat.py - определяет тип чата type_chat(message):
-Личный
-Группы
-Канал
type_msg.py - определяет тип сообщения type_msg(message):
-Текст
-Фото
-Стикер
-...
Второй модуль loggers:
logs.py - создает логгеры, три кастомных уровня и 4 обычных. Он может создавать
-NEW_USER
-LEAVE_USER
-START показывает
Последний модуль validators:
email_valid.py - содержит проверку на почту, для будущих добавлений [valid_email(email)]
normal_word.py - проводит к виду "Видообразование" [normal_words]
url_valid.py -

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 KiB

Binary file not shown.

View File

@@ -2,7 +2,7 @@
# Инициализация модуля bd_func, для функция с БД
from aiogram import types
from BotLibrary import username
from BotLibrary.validators import username
from ProjectsFiles import Permissions
from .bd_add_user import *

View File

@@ -5,7 +5,7 @@ import sqlite3
from aiogram import types
from datetime import timezone, datetime, timedelta
from BotLibrary import types_message
from BotLibrary import type_msg
from ProjectsFiles import BotVar
# Настройка экспорта в модули
@@ -31,7 +31,7 @@ async def update_user_messages(message: types.Message, bd_name: str = BotVar.bd_
current_month = now.month
current_year = now.year
last_message = message.text or types_message(message)
last_message = message.text or type_msg(message)
last_message_id = message.message_id
if result:

20
main.py
View File

@@ -4,34 +4,18 @@
import asyncio
from BotLibrary import *
from BotCode import router as main_router
from SQLite3 import create_user_db
# Запуск основного кода
async def main():
# Функция создания логеров и получения информации о боте
await setup_logger()
await bot_get_info()
Logs.start(text=f"Начало запуска бота @{BotInfo.username}...")
bot_info_out()
# Автоматическое создание базы данных при отсутствии
await create_user_db()
# Создание пустых директорий
await setup_directories()
# Функция установки
await setup()
# Подключение главного маршрутизатора
dp.include_router(main_router)
# Нужно ли удалить веб-хук
if Permissions.delete_webhook:
await bot.delete_webhook()
# Включение опроса бота
await dp.start_polling(bot)
# Вечная загрузка бота
if __name__ == "__main__":
asyncio.run(main())