diff --git a/BotCode/__init__.py b/BotCode/__init__.py index 381b080..f8ba19b 100644 --- a/BotCode/__init__.py +++ b/BotCode/__init__.py @@ -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") @@ -15,4 +12,4 @@ router = Router(name="main_router") router.include_routers( all_routers, inline_routers, -) +) \ No newline at end of file diff --git a/BotCode/easteggs/__init__.py b/BotCode/easteggs/__init__.py new file mode 100644 index 0000000..7af69db --- /dev/null +++ b/BotCode/easteggs/__init__.py @@ -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) diff --git a/BotCode/easteggs/holidays/__init__.py b/BotCode/easteggs/holidays/__init__.py new file mode 100644 index 0000000..e38f285 --- /dev/null +++ b/BotCode/easteggs/holidays/__init__.py @@ -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, +) diff --git a/BotCode/easteggs/holidays/march8.py b/BotCode/easteggs/holidays/march8.py new file mode 100644 index 0000000..202bb83 --- /dev/null +++ b/BotCode/easteggs/holidays/march8.py @@ -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 = ("""🌸 С 8 Марта! 🌸 +Вы наши дорогие девушки, мы хотим поздравить вас в честь этого праздника! +Пусть этот день принесёт вам море улыбок, приятные воспоминания и теплые слова! 🌷 +Пусть каждый день будет наполнен радостью, счастьем и любовью, а мечты сбываются легко и красиво! 💐 + +Оставайтесь такими же прекрасными, вдохновляющими и неповторимыми! ✨ С праздником! 💖 +Вы и сами знаете, что нужно сделать. Тогда Вперед за Истиной, наши любимые!""") +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, +) \ No newline at end of file diff --git a/BotCode/keyboards/inline_kb/__init__.py b/BotCode/keyboards/inline_kb/__init__.py index 05e8bc1..51e2ddd 100644 --- a/BotCode/keyboards/inline_kb/__init__.py +++ b/BotCode/keyboards/inline_kb/__init__.py @@ -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 diff --git a/BotCode/keyboards/inline_kb/march8_inline_kb.py b/BotCode/keyboards/inline_kb/march8_inline_kb.py new file mode 100644 index 0000000..6cfc069 --- /dev/null +++ b/BotCode/keyboards/inline_kb/march8_inline_kb.py @@ -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() \ No newline at end of file diff --git a/BotCode/routers/commands/adm_cmd/all_cmd.py b/BotCode/routers/commands/adm_cmd/all_cmd.py index 4c4cf51..d487f3d 100644 --- a/BotCode/routers/commands/adm_cmd/all_cmd.py +++ b/BotCode/routers/commands/adm_cmd/all_cmd.py @@ -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)], ) diff --git a/BotCode/routers/commands/adm_cmd/ban_cmd.py b/BotCode/routers/commands/adm_cmd/ban_cmd.py index 2a185af..df796cb 100644 --- a/BotCode/routers/commands/adm_cmd/ban_cmd.py +++ b/BotCode/routers/commands/adm_cmd/ban_cmd.py @@ -43,6 +43,5 @@ ban_cmd = CommandHandler( name="ban", description="Блокировка пользователя", keywords=["ban", "бан", "banhammer", "ифтрфььук", "ифт"], - callbackdata=["keywords"], media="command", func=[ban_user], ) diff --git a/BotCode/routers/commands/easteggs_cmd/__init__.py b/BotCode/routers/commands/easteggs_cmd/__init__.py index 54dc1b7..bf0d6cb 100644 --- a/BotCode/routers/commands/easteggs_cmd/__init__.py +++ b/BotCode/routers/commands/easteggs_cmd/__init__.py @@ -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, ) diff --git a/BotCode/routers/commands/easteggs_cmd/finaki_succub.py b/BotCode/routers/commands/easteggs_cmd/finaki_succub.py new file mode 100644 index 0000000..03ef116 --- /dev/null +++ b/BotCode/routers/commands/easteggs_cmd/finaki_succub.py @@ -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", +) \ No newline at end of file diff --git a/BotCode/routers/commands/easteggs_cmd/kataz_pidaraz_2020.py b/BotCode/routers/commands/easteggs_cmd/kataz_pidaraz_2020.py index b3f70f3..69a44ee 100644 --- a/BotCode/routers/commands/easteggs_cmd/kataz_pidaraz_2020.py +++ b/BotCode/routers/commands/easteggs_cmd/kataz_pidaraz_2020.py @@ -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", diff --git a/BotCode/routers/commands/easteggs_cmd/polina_anketa.py b/BotCode/routers/commands/easteggs_cmd/polina_anketa.py index 0a25455..c92b10a 100644 --- a/BotCode/routers/commands/easteggs_cmd/polina_anketa.py +++ b/BotCode/routers/commands/easteggs_cmd/polina_anketa.py @@ -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", diff --git a/BotCode/routers/commands/user_cmd/help_cmd.py b/BotCode/routers/commands/user_cmd/help_cmd.py index eaa87a6..91fa736 100644 --- a/BotCode/routers/commands/user_cmd/help_cmd.py +++ b/BotCode/routers/commands/user_cmd/help_cmd.py @@ -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="Привет! Это команда помощи. Тут ты можешь узнать, как пользоваться ботом.", ) diff --git a/BotCode/routers/commands/user_cmd/my_cmd.py b/BotCode/routers/commands/user_cmd/my_cmd.py index 6a66de2..d80e07d 100644 --- a/BotCode/routers/commands/user_cmd/my_cmd.py +++ b/BotCode/routers/commands/user_cmd/my_cmd.py @@ -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", diff --git a/BotCode/routers/commands/user_cmd/start_cmd.py b/BotCode/routers/commands/user_cmd/start_cmd.py index cb5db75..f3fc8f4 100644 --- a/BotCode/routers/commands/user_cmd/start_cmd.py +++ b/BotCode/routers/commands/user_cmd/start_cmd.py @@ -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="Привет! Вот группа фото!", ) diff --git a/BotCode/routers/commands/user_cmd/start_time_cmd.py b/BotCode/routers/commands/user_cmd/start_time_cmd.py index b6f485c..68c8527 100644 --- a/BotCode/routers/commands/user_cmd/start_time_cmd.py +++ b/BotCode/routers/commands/user_cmd/start_time_cmd.py @@ -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Хост: {dp['started_at']} " f"\nМСК: {dp['started_at_msk']}", diff --git a/BotCode/routers/commands/user_cmd/stats.py b/BotCode/routers/commands/user_cmd/stats.py index 0876988..ff2873e 100644 --- a/BotCode/routers/commands/user_cmd/stats.py +++ b/BotCode/routers/commands/user_cmd/stats.py @@ -31,6 +31,5 @@ stats_cmd = CommandHandler( name="stats", description="Вывод статистики о пользователи", keywords=["stats", "ыефеы", "cnfnf", "стата", "Кто я", "Rnj z", "vjbcjj,otybz", "моисообщения"], - callbackdata=["keywords"], media="command", func=[send_stats], ) diff --git a/BotCode/routers/commands/user_cmd/weather_cmd.py b/BotCode/routers/commands/user_cmd/weather_cmd.py index 294b847..400d821 100644 --- a/BotCode/routers/commands/user_cmd/weather_cmd.py +++ b/BotCode/routers/commands/user_cmd/weather_cmd.py @@ -10,7 +10,6 @@ weather_cmd = CommandHandler( name="weather", description="Погода", keywords=["weather", "gjujlf", "цуферук", "погода"], - callbackdata=["keywords"], media="command", func=[get_weather], ) diff --git a/BotCode/routers/common/messages.py b/BotCode/routers/common/messages.py index cea6d9c..82efa87 100644 --- a/BotCode/routers/common/messages.py +++ b/BotCode/routers/common/messages.py @@ -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) diff --git a/BotLibrary/__init__.py b/BotLibrary/__init__.py index 9964e1a..a294390 100644 --- a/BotLibrary/__init__.py +++ b/BotLibrary/__init__.py @@ -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() diff --git a/BotLibrary/analytics/type_msg.py b/BotLibrary/analytics/type_msg.py index 2c12433..a21dcf4 100644 --- a/BotLibrary/analytics/type_msg.py +++ b/BotLibrary/analytics/type_msg.py @@ -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: "Изменение таймера авто-удаления сообщения", } # Получение типа сообщения diff --git a/BotLibrary/loggers/__init__.py b/BotLibrary/loggers/__init__.py index e8d08ed..6889e52 100644 --- a/BotLibrary/loggers/__init__.py +++ b/BotLibrary/loggers/__init__.py @@ -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 * diff --git a/BotLibrary/loggers/custom_loggers.py b/BotLibrary/loggers/custom_loggers.py index 91bee06..994805d 100644 --- a/BotLibrary/loggers/custom_loggers.py +++ b/BotLibrary/loggers/custom_loggers.py @@ -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)) diff --git a/BotLibrary/loggers/logs.py b/BotLibrary/loggers/logs.py index 5505d3d..6007a3d 100644 --- a/BotLibrary/loggers/logs.py +++ b/BotLibrary/loggers/logs.py @@ -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, diff --git a/BotLibrary/loggers/msg_logger.py b/BotLibrary/loggers/msg_logger.py deleted file mode 100644 index 43e6175..0000000 --- a/BotLibrary/loggers/msg_logger.py +++ /dev/null @@ -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 diff --git a/BotLibrary/loggers/start_info_out.py b/BotLibrary/loggers/start_info_out.py deleted file mode 100644 index 13dd648..0000000 --- a/BotLibrary/loggers/start_info_out.py +++ /dev/null @@ -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}") diff --git a/BotLibrary/samples/inline_kb_sample.py b/BotLibrary/samples/inline_kb_sample.py index 35424b2..c1dd60d 100644 --- a/BotLibrary/samples/inline_kb_sample.py +++ b/BotLibrary/samples/inline_kb_sample.py @@ -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 diff --git a/BotLibrary/samples/reply_kb_sample.py b/BotLibrary/samples/reply_kb_sample.py index 6cb42bc..ad4b9c9 100644 --- a/BotLibrary/samples/reply_kb_sample.py +++ b/BotLibrary/samples/reply_kb_sample.py @@ -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 diff --git a/BotLibrary/samples/user_cmd_class.py b/BotLibrary/samples/user_cmd_class.py index c8ea3b6..2d89326 100644 --- a/BotLibrary/samples/user_cmd_class.py +++ b/BotLibrary/samples/user_cmd_class.py @@ -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("", 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}") diff --git a/BotLibrary/system/bot_edit.py b/BotLibrary/system/bot_edit.py index d9d330b..ee91e51 100644 --- a/BotLibrary/system/bot_edit.py +++ b/BotLibrary/system/bot_edit.py @@ -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) \ No newline at end of file diff --git a/BotLibrary/system/bots.py b/BotLibrary/system/bots.py index 703de91..167a1e6 100644 --- a/BotLibrary/system/bots.py +++ b/BotLibrary/system/bots.py @@ -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"] = {} diff --git a/BotLibrary/timer/start_time.py b/BotLibrary/timer/start_time.py index ff0a0a6..f065d76 100644 --- a/BotLibrary/timer/start_time.py +++ b/BotLibrary/timer/start_time.py @@ -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) diff --git a/BotLibrary/validators/email_valid.py b/BotLibrary/validators/email_valid.py index bbe24de..9782d30 100644 --- a/BotLibrary/validators/email_valid.py +++ b/BotLibrary/validators/email_valid.py @@ -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 None + 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 \ No newline at end of file diff --git a/BotLibrary/validators/normal_word.py b/BotLibrary/validators/normal_word.py index 7c8c2bc..c72a83a 100644 --- a/BotLibrary/validators/normal_word.py +++ b/BotLibrary/validators/normal_word.py @@ -1,5 +1,20 @@ # BotLibrary/validators/normal_word.py # Нормализирует вид слова автоматически -async def normal_words(word : str = "Тестовое слово") -> str: - return word.lower().capitalize() +# Настройка экспорта из этого модуля +__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 \ No newline at end of file diff --git a/BotLibrary/validators/url_valid.py b/BotLibrary/validators/url_valid.py index 4d939d2..609e2e2 100644 --- a/BotLibrary/validators/url_valid.py +++ b/BotLibrary/validators/url_valid.py @@ -25,5 +25,27 @@ def valid_url(url: str) -> bool: # Функция, что дает тексту ссылку на HTML -def url_to_text(text: str = "Тест", url: str = "www.google.com") -> str: - return f'{text}' +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'{text}' + + except ValueError as e: + # Импортируем Logs внутри функции, чтобы избежать циклического импорта + from ..loggers.custom_loggers import Logs + # Логируем ошибку с использованием Logs.error, как указано + Logs.error(text=f"Ошибка при создании ссылки: {e}", log_type="InvalidURL") + raise e # Перебрасываем ошибку выше для дальнейшей обработки или уведомления \ No newline at end of file diff --git a/BotLibrary/validators/username.py b/BotLibrary/validators/username.py index 96c0dd3..6f1cfc0 100644 --- a/BotLibrary/validators/username.py +++ b/BotLibrary/validators/username.py @@ -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: Если в сообщении отсутствует информация о пользователе. """ - 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 отсутствует + try: + if message.from_user: + return f"@{message.from_user.username}" if message.from_user.username else f"@{message.from_user.id}" + raise ValueError("Информация о пользователе отсутствует в сообщении.") + + except ValueError as e: + # Логируем ошибку с использованием Logs.error + raise e # Перебрасываем ошибку выше для дальнейшей обработки # Функция получение имени пользователя + ссылка на него def username_to_text(message: Message) -> str: - return f'{message.from_user.full_name}' + """ + Преобразует информацию о пользователе в строку с HTML-ссылкой. + + :param message: Объект сообщения из aiogram. + :return: Строка с HTML-кодом для ссылки на пользователя. + :raises ValueError: Если в сообщении отсутствует информация о пользователе. + """ + try: + if message.from_user: + return f'{message.from_user.full_name}' + raise ValueError("Информация о пользователе отсутствует в сообщении.") + + except ValueError as e: + # Логируем ошибку с использованием Logs.error + raise e # Перебрасываем ошибку выше для дальнейшей обработки diff --git a/Documentation/docs.md b/Documentation/docs.md new file mode 100644 index 0000000..cad3735 --- /dev/null +++ b/Documentation/docs.md @@ -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 - \ No newline at end of file diff --git a/ProjectsFiles/media/Banners/finaki_my.jpeg b/ProjectsFiles/media/Banners/finaki_my.jpeg new file mode 100644 index 0000000..76ceca6 Binary files /dev/null and b/ProjectsFiles/media/Banners/finaki_my.jpeg differ diff --git a/ProjectsFiles/media/Banners/march8_banner.jpeg b/ProjectsFiles/media/Banners/march8_banner.jpeg new file mode 100644 index 0000000..2dfcf4f Binary files /dev/null and b/ProjectsFiles/media/Banners/march8_banner.jpeg differ diff --git a/ProjectsFiles/media/Banners/march8_finaki_banner.jpeg b/ProjectsFiles/media/Banners/march8_finaki_banner.jpeg new file mode 100644 index 0000000..8d81166 Binary files /dev/null and b/ProjectsFiles/media/Banners/march8_finaki_banner.jpeg differ diff --git a/ProjectsFiles/media/Banners/march8_finik_banner.jpeg b/ProjectsFiles/media/Banners/march8_finik_banner.jpeg new file mode 100644 index 0000000..6262a9c Binary files /dev/null and b/ProjectsFiles/media/Banners/march8_finik_banner.jpeg differ diff --git a/ProjectsFiles/media/Banners/march8_kataz_banner.png b/ProjectsFiles/media/Banners/march8_kataz_banner.png new file mode 100644 index 0000000..b401f33 Binary files /dev/null and b/ProjectsFiles/media/Banners/march8_kataz_banner.png differ diff --git a/ProjectsFiles/media/Banners/march8_lostik_banner.png b/ProjectsFiles/media/Banners/march8_lostik_banner.png new file mode 100644 index 0000000..20f4ba6 Binary files /dev/null and b/ProjectsFiles/media/Banners/march8_lostik_banner.png differ diff --git a/ProjectsFiles/media/Banners/march8_polina_banner.png b/ProjectsFiles/media/Banners/march8_polina_banner.png new file mode 100644 index 0000000..1e9423f Binary files /dev/null and b/ProjectsFiles/media/Banners/march8_polina_banner.png differ diff --git a/SQLite3/bd.db b/SQLite3/bd.db index 213f41e..f2f49a4 100644 Binary files a/SQLite3/bd.db and b/SQLite3/bd.db differ diff --git a/SQLite3/bd_func/__init__.py b/SQLite3/bd_func/__init__.py index 0240b5e..cdbea3d 100644 --- a/SQLite3/bd_func/__init__.py +++ b/SQLite3/bd_func/__init__.py @@ -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 * diff --git a/SQLite3/bd_func/bd_update_user_msg.py b/SQLite3/bd_func/bd_update_user_msg.py index a95ffed..55c5178 100644 --- a/SQLite3/bd_func/bd_update_user_msg.py +++ b/SQLite3/bd_func/bd_update_user_msg.py @@ -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: diff --git a/main.py b/main.py index f8fdbe0..2219858 100644 --- a/main.py +++ b/main.py @@ -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())