diff --git a/.idea/PRIMOWORLD.iml b/.idea/PRIMOWORLD.iml
index 541e011..e96faea 100644
--- a/.idea/PRIMOWORLD.iml
+++ b/.idea/PRIMOWORLD.iml
@@ -23,6 +23,7 @@
+
diff --git a/BotCode/inline/reklama.py b/BotCode/inline/reklama.py
index 8956fa9..be080a9 100644
--- a/BotCode/inline/reklama.py
+++ b/BotCode/inline/reklama.py
@@ -1,8 +1,9 @@
# BotCode/inline/reklama.py
# Работа с инлайн запросами на рекламу
-from aiogram import Router, types
-from aiogram.types import InlineQueryResultPhoto
+from aiogram import Router
+from aiogram.types import (InlineQueryResultPhoto, InlineQuery, CallbackQuery,
+ InlineKeyboardMarkup, InlineKeyboardButton)
from BotLibrary import bot
# Настройка экспорта в модули
@@ -14,13 +15,13 @@ f"""Это сообщение с изображением и инлайн кно
@router.callback_query(lambda c: c.data == 'button_1')
-async def process_callback_button(callback_query: types.CallbackQuery) -> None:
+async def process_callback_button(callback_query: CallbackQuery) -> None:
await bot.answer_callback_query(callback_query.id, text="Вы нажали первую кнопку!")
await bot.send_message(callback_query.from_user.id, "Ответ на вашу кнопку.")
@router.inline_query()
-async def inline_echo(inline_query: types.InlineQuery) -> None:
+async def inline_echo(inline_query: InlineQuery) -> None:
# Содержимое запроса
query = inline_query.query
@@ -36,10 +37,10 @@ async def inline_echo(inline_query: types.InlineQuery) -> None:
photo_url=image_url, # URL изображения
thumbnail_url=image_url, # Миниатюра изображения
caption=text_msg, # Текст, который будет показываться под изображением
- reply_markup=types.InlineKeyboardMarkup(
+ reply_markup=InlineKeyboardMarkup(
inline_keyboard=[
- [types.InlineKeyboardButton(text="Посмотреть инфо-канал", url="https://t.me/adeptusfiziks")],
- [types.InlineKeyboardButton(text="Вторая кнопка", callback_data="button_1")],
+ [InlineKeyboardButton(text="Посмотреть инфо-канал", url="https://t.me/adeptusfiziks")],
+ [InlineKeyboardButton(text="Вторая кнопка", callback_data="button_1")],
]
)
)
diff --git a/BotCode/routers/commands/adm_cmd/ban_cmd.py b/BotCode/routers/commands/adm_cmd/ban_cmd.py
index b7cd099..12e2d64 100644
--- a/BotCode/routers/commands/adm_cmd/ban_cmd.py
+++ b/BotCode/routers/commands/adm_cmd/ban_cmd.py
@@ -2,15 +2,14 @@
# Работа с командой /stats, для получения информации о себе
from aiogram import types
-from BotLibrary import CommandHandler, bot
-from SQLite3 import status_user
+from BotLibrary import CommandHandler, bot, db
# Настройки экспорта в модули
__all__ = ("ban_cmd",)
# Функция блокировки пользователя
async def ban_user(message: types.Message, *args, **kwargs) -> None:
- status = await status_user(message)
+ status = db.get_user_status(message)
if status not in ('Пользователь', 'Забаннен'):
# Проверка, что команда вызвана с упоминанием пользователя
args = message.text.split()
diff --git a/BotCode/routers/commands/user_cmd/weather_cmd.py b/BotCode/routers/commands/user_cmd/weather_cmd.py
index 400d821..41264c0 100644
--- a/BotCode/routers/commands/user_cmd/weather_cmd.py
+++ b/BotCode/routers/commands/user_cmd/weather_cmd.py
@@ -1,5 +1,5 @@
# BotCode/routers/commands/user_cmd/start_time_cmd.py
-#
+# Команда на выдачу погоды определенного города
from BotLibrary import CommandHandler
from BotCode.utils import get_weather
diff --git a/BotCode/routers/common/messages.py b/BotCode/routers/common/messages.py
index d34778e..574880b 100644
--- a/BotCode/routers/common/messages.py
+++ b/BotCode/routers/common/messages.py
@@ -3,7 +3,6 @@
from aiogram import Router, types
from BotLibrary import *
-from SQLite3 import base_sql, status_user
# Настройка экспорта модулей и роутера
__all__ = ("router",)
@@ -12,6 +11,6 @@ router = Router(name="common_msg_router")
# Обработчик всех сообщений
@router.message()
async def all_messages(message: types.Message) -> None:
- await base_sql(message)
- await status_user(message)
+ db.update_user(message)
+ db.update_user_messages(message)
Logs.msg(message)
diff --git a/BotCode/utils/admin_list.py b/BotCode/utils/admin_list.py
index 86e815d..40b7689 100644
--- a/BotCode/utils/admin_list.py
+++ b/BotCode/utils/admin_list.py
@@ -1,22 +1,34 @@
# BotCode/utils/admin_lists.py
# Составления листа администраторов
+from aiogram.types import Message
from BotLibrary import bot
+from ProjectsFiles import BotVar
# Настройки экспорта в модули
__all__ = ("admin_lists",)
+async def admin_lists(chat_id: int = None, message: Message = None) -> str:
+ """
+ Функция составления словаря администраторов.
-# Функция составления словаря администраторов
-async def admin_lists(chat_id: int) -> str:
+ :param message: Объект сообщения от пользователя.
+ :param chat_id: ID-чата в котором будет проводиться работа.
+ :return: Строка с юзерами администрации.
+ """
+ chat_id = chat_id if isinstance(chat_id, int) else message.chat.id
admins = await bot.get_chat_administrators(chat_id)
+
# Формируем список упоминаний администраторов
admin_mentions = []
for admin in admins:
if admin.user.is_bot:
continue
- admin_mentions.append(
+ if BotVar.parse_mode == "HTML":
+ admin_mentions.append(
f"@{admin.user.username}" if admin.user.username else f"{admin.user.full_name}")
-
+ elif BotVar.parse_mode == "MarkdownV2":
+ admin_mentions.append(
+ f"@{admin.user.username}" if admin.user.username else f"[{admin.user.full_name}](tg://user?id={admin.user.id})")
admins_text = ", ".join(admin_mentions) if admin_mentions else "Нет администраторов"
return admins_text
diff --git a/BotCode/utils/all_admins_hide.py b/BotCode/utils/all_admins_hide.py
index 2e25dbb..f1b95f9 100644
--- a/BotCode/utils/all_admins_hide.py
+++ b/BotCode/utils/all_admins_hide.py
@@ -8,18 +8,28 @@ from BotLibrary import bot
# Настройки экспорта в модули
__all__ = ("hidden_admins_message",)
-
-# Функция составления словаря администраторов
async def hidden_admins_message(message: types.Message = None,
chat_id: int = None,
text: str = "",
msg: bool = True, *args) -> str | None:
+ """
+ Формирует скрытые ссылки на администраторов чата в Markdown-разметке.
+
+ :param message: Объект сообщения от пользователя (если chat_id не указан, ID чата берется из него).
+ :param chat_id: ID чата, в котором нужно получить список администраторов (если не указан, берется из message).
+ :param text: Дополнительный текст, который будет добавлен к результату.
+ :param msg: Определяет, возвращать ли результат (True) или отправлять его в чат (False).
+ :param args: Дополнительные аргументы (не используются, оставлены для совместимости с шаблоном).
+ :return: Строка со скрытыми ссылками на администраторов и добавленным текстом (если msg=True), иначе None.
+ """
chat_id = chat_id if isinstance(chat_id, int) else message.chat.id
admins = await bot.get_chat_administrators(chat_id)
+
hidden_links = "".join(
markdown.hide_link(f"tg://user?id={admin.user.id}")
for admin in admins if not admin.user.is_bot
)
+
result = f"{hidden_links}{text}"
if msg:
return result
diff --git a/BotCode/utils/notification/__init__.py b/BotCode/utils/notification/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/BotCode/utils/weather_api.py b/BotCode/utils/weather_api.py
index cbf3907..7734930 100644
--- a/BotCode/utils/weather_api.py
+++ b/BotCode/utils/weather_api.py
@@ -1,10 +1,17 @@
import aiohttp
+from aiogram.types import Message
from ProjectsFiles import weather_api_key
# Настройки экспорта в модули
__all__ = ("get_weather",)
-async def get_weather(message, *args) -> str:
+async def get_weather(message: Message, *args) -> str:
+ """
+ Обрабатывает запрос о погоде для указанного города и возвращает информацию о текущей погоде.
+
+ :param message: Объект сообщения от пользователя.
+ :return: Возвращает ответ о погоде в указанном городе.
+ """
# Извлекаем город из сообщения
command_parts = message.text.split(maxsplit=1)
print(command_parts[1])
@@ -33,10 +40,10 @@ async def get_weather(message, *args) -> str:
wind = data["wind"]["speed"]
weather_today: str = (f"Погода {city}\n"
- f"☁️Погода: {weather}\n"
- f"🌡Температура: {temp}°C\n"
- f"💧Влажность: {humidity}%\n"
- f"💨Скорость ветра: {wind} м/с")
+ f"☁️Погода: {weather}\n"
+ f"🌡Температура: {temp}°C\n"
+ f"💧Влажность: {humidity}%\n"
+ f"💨Скорость ветра: {wind} м/с")
await message.answer(weather_today)
return weather_today
except Exception as e:
diff --git a/BotLibrary/__init__.py b/BotLibrary/__init__.py
index a294390..2317c8f 100644
--- a/BotLibrary/__init__.py
+++ b/BotLibrary/__init__.py
@@ -5,37 +5,7 @@
from .analytics import *
from .loggers import *
from .samples import *
+from .sql import *
from .system import *
from .timer import *
from .validators 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_chat.py b/BotLibrary/analytics/type_chat.py
index 70cc965..31e4362 100644
--- a/BotLibrary/analytics/type_chat.py
+++ b/BotLibrary/analytics/type_chat.py
@@ -1,25 +1,23 @@
# BotLibrary/analytics/type_chat.py
# Определение типа чата
-from aiogram import types
+from aiogram.types import Message
# Настройка экспорта в модули
__all__ = ("type_chat",)
-# Проверка на тип чата
-async def type_chat(message: types.Message) -> str:
+async def type_chat(message: Message) -> str:
"""
- Преобразует информацию о чате в понятные значения.
+ Преобразует информацию о чате в его тип на русском языке.
- :param message: Объект сообщения из aiogram.
+ :param message: Объект сообщения из aiogram, содержащий информацию о чате.
:return: Тип чата строкой.
"""
- chat_type: str = message.chat.type
- if chat_type == "private":
- return "Личный"
- elif chat_type == "group" or chat_type == "supergroup":
- return "Группа"
- elif chat_type == "channel":
- return "Канал"
- else:
- return "Неизвестный тип чата."
+ chat_types: dict[str, str] = {
+ "private": "Личный",
+ "group": "Группа",
+ "supergroup": "Группа",
+ "channel": "Канал",
+ }
+
+ return chat_types.get(message.chat.type, "Неизвестный тип чата")
diff --git a/BotLibrary/analytics/type_msg.py b/BotLibrary/analytics/type_msg.py
index 4a28287..f12e9da 100644
--- a/BotLibrary/analytics/type_msg.py
+++ b/BotLibrary/analytics/type_msg.py
@@ -6,7 +6,6 @@ from aiogram.types import ContentType, Message
# Настройка экспорта из модуля
__all__ = ("type_msg",)
-# Функция определения типа сообщения
def type_msg(message: Message) -> str:
"""
Функция для определения типа сообщения на основе его содержимого.
@@ -50,7 +49,7 @@ def type_msg(message: Message) -> str:
ContentType.INVOICE: "Счет",
ContentType.SUCCESSFUL_PAYMENT: "Успешный платеж",
ContentType.REFUNDED_PAYMENT: "Возврат платежа",
- ContentType.USERS_SHARED: "Пользователи поделились",
+ ContentType.USERS_SHARED: "Пользователь поделился",
ContentType.CHAT_SHARED: "Чат был передан",
ContentType.CONNECTED_WEBSITE: "Подключенный веб-сайт",
ContentType.WRITE_ACCESS_ALLOWED: "Разрешение на запись",
@@ -77,9 +76,20 @@ def type_msg(message: Message) -> str:
# Получение типа сообщения
message_type: str = message.content_type
+
# Если это контакт, добавляем номер телефона
if message_type == ContentType.CONTACT and message.contact:
return f"{content_types.get(message_type, 'Контакт')}: {message.contact.phone_number}"
+ # Если это пользователи, добавляем их ID
+ if message_type == ContentType.USERS_SHARED and message.users_shared:
+ user_ids = ", ".join(map(str, message.users_shared.user_ids))
+ return f"{content_types.get(message_type, 'Пользователь поделился')}: {user_ids}"
+
+ # Если это переданный чат, добавляем его ID
+ if message_type == ContentType.CHAT_SHARED and message.chat_shared:
+ return f"{content_types.get(message_type, 'Чат был передан')}: {message.chat_shared.chat_id}"
+
+
# Возвращаем описание типа сообщения, если оно есть в словаре, иначе "Неизвестный тип"
return content_types.get(message_type, "Неизвестный тип")
diff --git a/BotLibrary/loggers/__init__.py b/BotLibrary/loggers/__init__.py
index c235a89..2e432b8 100644
--- a/BotLibrary/loggers/__init__.py
+++ b/BotLibrary/loggers/__init__.py
@@ -3,4 +3,3 @@
# Экспортирование модулей во внешние слои проекта
from .logs import *
-from .custom_loggers import *
diff --git a/BotLibrary/loggers/custom_loggers.py b/BotLibrary/loggers/custom_loggers.py
deleted file mode 100644
index c6e7134..0000000
--- a/BotLibrary/loggers/custom_loggers.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# BotLibrary/loggers/custom_loggers.py
-# Кастомные логгеры для проекта, с более стандартизированным использованием
-
-from time import sleep
-
-from aiogram import types
-from colorama import Fore
-from loguru import logger
-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",)
-
-
-class Logs:
- """Класс для логирования с разными уровнями через loguru."""
-
- @staticmethod
- def start(text: str = "Логирование!",
- system: str = "PRIMO",
- log_type: str = "AEP",
- user: str = "@Console") -> None:
- """
- Логирует сообщение на уровне START.
-
- :param text: Сообщение для логирования.
- :param system: Тип системы логирования.
- :param log_type: Тип лога (например, "Help").
- :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:
- """
- Логирует сообщение на уровне DEBUG.
-
- :param text: Сообщение для логирования.
- :param system: Тип системы логирования.
- :param log_type: Тип лога (например, "Help").
- :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:
- """
- Логирует сообщение на уровне INFO.
-
- :param text: Сообщение для логирования.
- :param system: Тип системы логирования.
- :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:
- """
- Логирует сообщение на уровне WARNING.
-
- :param text: Сообщение для логирования.
- :param system: Тип системы логирования.
- :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:
- """
- Логирует сообщение на уровне ERROR.
-
- :param text: Сообщение для логирования.
- :param system: Тип системы логирования.
- :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: types.Message,
- log_type: str = "Message",
- user: str = None,
- msg_type: str = None,
- permission: bool = BotLogs.permission) -> None:
- """
- Логирует сообщение, если оно не обработано.
-
- :param message: Сообщение от пользователя.
- :param log_type: Тип лога (по умолчанию "Message").
- :param permission: Разрешение на логирование (config).
- :param user: Получение пользователя (автоматически).
- :param msg_type: Получение типа сообщения (автоматически).
-.
- :return: Вывод сообщения об обычном сообщении пользователя.
- """
- # Получаем айди чата
- chat_id = message.chat.id
-
- # Получаем username или id пользователя
- if user is None:
- user: str = f"@{message.from_user.username or message.from_user.id}"
- if msg_type is None:
- 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"Получено сообщение из ({chat_id}) : {msg_type}")
- elif message.text is not None:
- Logs.info(log_type=log_type, user=user,
- text=f"Получено сообщение из ({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 6007a3d..c366992 100644
--- a/BotLibrary/loggers/logs.py
+++ b/BotLibrary/loggers/logs.py
@@ -1,107 +1,295 @@
# BotLibrary/loggers/logs.py
-# Создание логгеров и их шаблон для проекта
+# Кастомные логгеры для проекта, с более стандартизированным использованием
-import sys
from loguru import logger
-from ProjectsFiles import BotLogs, ProjectPath
+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__ = ("setup_logger",)
-
-# Создание обычного логгера + логгер в файл
-async def setup_logger(logging: bool = BotLogs.permission,
- to_file: bool = BotLogs.permission_to_file) -> None:
- """
- Настройка логгеров для проекта, выводящих логи в консоль и файлы.
- Логгеры конфигурируются в зависимости от настроек в конфигах проекта.
-
- Если разрешено логирование, добавляются логи для уровней DEBUG, INFO, WARNING, ERROR.
- И кастомные такие, как START, NEW_USER, LEAVE_USER
-
- :param logging: Разрешение на логирование в консоль (config)
- :param to_file: Разрешение на логирование в файл (config)
-
- :return: Создание логеров под различные уровни
- """
- logger.remove() # Удаляем все стандартные логгеры
+__all__ = ("Logs",)
- # Если есть разрешение, то он создает новые уровни
- if logging and BotLogs.permission_to_file:
- # Добавляем новый уровень START
- logger.level("START", no=25, color="white", icon="🔸")
- if logging and BotLogs.permission_new_user:
- # Добавляем новый уровень NEW_USER
- logger.level("NEW_USER", no=4, color="white", icon="👋")
- if logging and BotLogs.permission_leave_user:
- # Добавляем новый уровень LEAVE_USER
- logger.level("LEAVE_USER", no=3, color="white", icon="🫰")
+class Logs:
+ """Класс для логирования с разными уровнями через loguru."""
+ @staticmethod
+ def setup(logging: bool = BotLogs.permission,
+ to_file: bool = BotLogs.permission_to_file) -> None:
+ """
+ Настройка логгеров для проекта, выводящих логи в консоль и файлы.
+ Логгеры конфигурируются в зависимости от настроек в конфигах проекта.
+
+ Если разрешено логирование, добавляются логи для уровней DEBUG, INFO, WARNING, ERROR.
+ И кастомные такие, как START, NEW_USER, LEAVE_USER
+
+ :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 logging and BotLogs.permission_new_user:
+ # Добавляем новый уровень NEW_USER
+ logger.level("NEW_USER", no=4, color="white", icon="👋")
+ if logging and BotLogs.permission_leave_user:
+ # Добавляем новый уровень LEAVE_USER
+ logger.level("LEAVE_USER", no=3, color="white", icon="🫰")
+
+ # Настройка логирования в консоль для каждого уровня
+ if logging:
+ from sys import stderr
+ logger.add(stderr,
+ colorize=True,
+ format=BotLogs.start_text,
+ level="START",
+ filter=lambda record: record["level"].name == "START"
+ )
+ logger.add(stderr,
+ colorize=True,
+ format=BotLogs.debug_text,
+ level="DEBUG",
+ filter=lambda record: record["level"].name == "DEBUG")
+ logger.add(stderr,
+ colorize=True,
+ format=BotLogs.info_text,
+ level="INFO",
+ filter=lambda record: record["level"].name == "INFO")
+ logger.add(stderr,
+ colorize=True,
+ format=BotLogs.warning_text,
+ level="WARNING",
+ filter=lambda record: record["level"].name == "WARNING")
+ logger.add(stderr,
+ colorize=True,
+ format=BotLogs.error_text,
+ level="ERROR",
+ filter=lambda record: record["level"].name == "ERROR")
+
+ # Добавление логгера для записи в файл
+ if to_file:
+ logger.add(ProjectPath.start_log_file,
+ rotation=BotLogs.max_size,
+ format=BotLogs.start_text,
+ backtrace=True,
+ diagnose=True,
+ level="START",
+ filter=lambda record: record["level"].name == "START")
+ logger.add(ProjectPath.debug_log_file,
+ rotation=BotLogs.max_size,
+ format=BotLogs.debug_text,
+ backtrace=True,
+ diagnose=True,
+ level="DEBUG",
+ filter=lambda record: record["level"].name == "DEBUG")
+ logger.add(ProjectPath.info_log_file,
+ rotation=BotLogs.max_size,
+ format=BotLogs.info_text,
+ backtrace=True,
+ diagnose=True,
+ level="INFO",
+ filter=lambda record: record["level"].name == "INFO")
+ logger.add(ProjectPath.warning_log_file,
+ rotation=BotLogs.max_size,
+ format=BotLogs.warning_text,
+ backtrace=True,
+ diagnose=True,
+ level="WARNING",
+ filter=lambda record: record["level"].name == "WARNING")
+ logger.add(ProjectPath.error_log_file,
+ rotation=BotLogs.max_size,
+ format=BotLogs.error_text,
+ backtrace=True,
+ diagnose=True,
+ level="ERROR",
+ filter=lambda record: record["level"].name == "ERROR")
- # Настройка логирования в консоль для каждого уровня
- if logging:
- logger.add(sys.stderr,
- colorize=True,
- format=BotLogs.start_text,
- level="START",
- filter=lambda record: record["level"].name == "START"
- )
- logger.add(sys.stderr,
- colorize=True,
- format=BotLogs.debug_text,
- level="DEBUG",
- filter=lambda record: record["level"].name == "DEBUG")
- logger.add(sys.stderr,
- colorize=True,
- format=BotLogs.info_text,
- level="INFO",
- filter=lambda record: record["level"].name == "INFO")
- logger.add(sys.stderr,
- colorize=True,
- format=BotLogs.warning_text,
- level="WARNING",
- filter=lambda record: record["level"].name == "WARNING")
- logger.add(sys.stderr,
- colorize=True,
- format=BotLogs.error_text,
- level="ERROR",
- filter=lambda record: record["level"].name == "ERROR")
+ @staticmethod
+ def start(text: str = "Логирование!",
+ system: str = "PRIMO",
+ log_type: str = "AEP",
+ user: str = "@Console") -> None:
+ """
+ Логирует сообщение на уровне START.
+
+ :param text: Сообщение для логирования.
+ :param system: Тип системы логирования.
+ :param log_type: Тип лога (например, "Help").
+ :param user: Имя пользователя или источник вызова лога.
+
+ :return: Вывод сообщения об старте бота
+ """
+ logger.bind(system=system, user=user, log_type=log_type).log("START", text)
- # Добавление логгера для записи в файл
- if to_file:
- logger.add(ProjectPath.start_log_file,
- rotation=BotLogs.max_size,
- format=BotLogs.start_text,
- backtrace=True,
- diagnose=True,
- level="START",
- filter=lambda record: record["level"].name == "START")
- logger.add(ProjectPath.debug_log_file,
- rotation=BotLogs.max_size,
- format=BotLogs.debug_text,
- backtrace=True,
- diagnose=True,
- level="DEBUG",
- filter=lambda record: record["level"].name == "DEBUG")
- logger.add(ProjectPath.info_log_file,
- rotation=BotLogs.max_size,
- format=BotLogs.info_text,
- backtrace=True,
- diagnose=True,
- level="INFO",
- filter=lambda record: record["level"].name == "INFO")
- logger.add(ProjectPath.warning_log_file,
- rotation=BotLogs.max_size,
- format=BotLogs.warning_text,
- backtrace=True,
- diagnose=True,
- level="WARNING",
- filter=lambda record: record["level"].name == "WARNING")
- logger.add(ProjectPath.error_log_file,
- rotation=BotLogs.max_size,
- format=BotLogs.error_text,
- backtrace=True,
- diagnose=True,
- level="ERROR",
- filter=lambda record: record["level"].name == "ERROR")
+ @staticmethod
+ def debug(text: str = "Логирование!",
+ system: str = "DEBUG",
+ log_type: str = "Logs",
+ user: str = "@Console",
+ message: Message = None) -> None:
+ """
+ Логирует сообщение на уровне DEBUG.
+
+ :param text: Сообщение для логирования.
+ :param system: Тип системы логирования.
+ :param log_type: Тип лога (например, "Help").
+ :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:
+ """
+ Логирует сообщение на уровне INFO.
+
+ :param text: Сообщение для логирования.
+ :param system: Тип системы логирования.
+ :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:
+ """
+ Логирует сообщение на уровне WARNING.
+
+ :param text: Сообщение для логирования.
+ :param system: Тип системы логирования.
+ :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:
+ """
+ Логирует сообщение на уровне ERROR.
+
+ :param text: Сообщение для логирования.
+ :param system: Тип системы логирования.
+ :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",
+ user: str = None,
+ msg_type: str = None,
+ permission: bool = BotLogs.permission) -> None:
+ """
+ Логирует сообщение, если оно не обработано.
+
+ :param message: Сообщение от пользователя.
+ :param log_type: Тип лога (по умолчанию "Message").
+ :param permission: Разрешение на логирование (config).
+ :param user: Получение пользователя (автоматически).
+ :param msg_type: Получение типа сообщения (автоматически).
+.
+ :return: Вывод сообщения об обычном сообщении пользователя.
+ """
+ # Получаем айди чата
+ chat_id = message.chat.id
+
+ # Получаем username или id пользователя
+ if user is None:
+ user: str = f"@{message.from_user.username or message.from_user.id}"
+ if msg_type is None:
+ 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"Получено сообщение из ({chat_id}) : {msg_type}")
+ elif message.text is not None:
+ Logs.info(log_type=log_type, user=user,
+ text=f"Получено сообщение из ({chat_id}) : {message.text}")
+
+
+ @staticmethod
+ def console(console: bool = Permissions.start_info_console,
+ file: bool = Permissions.start_info_to_file,
+ path: str = ProjectPath.bot_info_log_file) -> None:
+ """
+ Собирает информацию о боте и выводит её в консоль, а также возвращает как строку.
+
+ :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:
+ from colorama import Fore
+ 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/samples/inline_kb_sample.py b/BotLibrary/samples/inline_kb_sample.py
index c1dd60d..1d12783 100644
--- a/BotLibrary/samples/inline_kb_sample.py
+++ b/BotLibrary/samples/inline_kb_sample.py
@@ -1,10 +1,13 @@
# BotLibrary/samples/inline_kb_sample.py
# Шаблон для создания инлайн клавиатур
-from aiogram.types import InlineKeyboardMarkup, ReplyKeyboardRemove
+from aiogram.types import InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
from typing import List, Tuple, Optional
+# Настройка экспорта в модули
+__all__ = ("BaseInlineKeyboard",)
+
class BaseInlineKeyboard:
def __init__(self, buttons: List[Tuple[str, Optional[str], Optional[str]]], row_width: int = 1):
"""
@@ -17,7 +20,7 @@ class BaseInlineKeyboard:
def get_keyboard(self) -> InlineKeyboardMarkup:
"""
Создаёт инлайн-клавиатуру и возвращает её вместе с объектом для удаления reply-клавиатуры.
- :return: кортеж (InlineKeyboardMarkup, ReplyKeyboardRemove)
+ :return: кортеж InlineKeyboardMarkup
"""
ikb = InlineKeyboardBuilder()
for text, url, callback_data in self.buttons:
diff --git a/BotLibrary/samples/reply_kb_sample.py b/BotLibrary/samples/reply_kb_sample.py
index ad4b9c9..046ca21 100644
--- a/BotLibrary/samples/reply_kb_sample.py
+++ b/BotLibrary/samples/reply_kb_sample.py
@@ -5,6 +5,9 @@ from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, KeyboardButtonPol
from aiogram.utils.keyboard import ReplyKeyboardBuilder
from typing import List, Union, Tuple, Optional, Dict, Any
+# Настройка экспорта в модули
+__all__ = ("BaseReplyKeyboard",)
+
class BaseReplyKeyboard:
def __init__(
self,
@@ -100,4 +103,4 @@ class BaseReplyKeyboard:
buttons.append(KeyboardButton(text=button))
rkb.row(*buttons)
- return rkb.as_markup(resize_keyboard=self.resize_keyboard, one_time_keyboard=self.one_time_keyboard)
\ No newline at end of file
+ return rkb.as_markup(resize_keyboard=self.resize_keyboard, one_time_keyboard=self.one_time_keyboard)
diff --git a/BotLibrary/samples/user_cmd_class.py b/BotLibrary/samples/user_cmd_class.py
index 3536223..6559032 100644
--- a/BotLibrary/samples/user_cmd_class.py
+++ b/BotLibrary/samples/user_cmd_class.py
@@ -11,16 +11,47 @@ from typing import Optional, Callable
from ..loggers import Logs
from ..validators import username, valid_url
from ProjectsFiles import BotVar
-from SQLite3 import base_sql
+from ..sql import db
# Настройки экспорта в модули
__all__ = ("CommandHandler",)
class CommandHandler:
+ """
+ Класс для создания и управления командами Telegram-бота.
+
+ Этот класс позволяет создавать команды с различными настройками, включая
+ текстовые сообщения, медиафайлы, клавиатуры, выполнение функций и обработку
+ callback-запросов.
+
+ :param name: Название команды.
+ :param keywords: Список ключевых слов, вызывающих команду.
+ :param func: Список функций, которые выполняются при вызове команды.
+ :param text_msg: Текстовое сообщение, которое отправляется в ответ на команду.
+ :param chat_action: Флаг отправки анимации набора текста перед ответом.
+ :param description: Описание команды.
+ :param tg_links: Флаг обработки ссылок на пользователей в тексте.
+ :param keyboard: Клавиатура, привязанная к команде.
+ :param prefix: Префикс команды (по умолчанию `BotVar.prefix`).
+ :param callbackdata: Список callback-данных, связанных с командой.
+ :param only_admin: Флаг, разрешающий использование команды только администраторам.
+ :param ignore_case: Флаг игнорирования регистра в ключевых словах.
+ :param activate_keywords: Флаг активации команды по ключевым словам.
+ :param delete_msg: Флаг удаления исходного сообщения после обработки команды.
+ :param activate_commands: Флаг активации команды через стандартный обработчик команд.
+ :param activate_callback: Флаг активации обработки callback-запросов.
+ :param media: Тип медиафайла, который отправляется (`"message"`, `"photo"`, `"video"`, и т. д.).
+ :param path_to_media: Путь к медиафайлу (или список путей).
+ :param parse_mode: Форматирование текста (`Markdown`, `HTML` и т. д.).
+ :param disable_notification: Флаг отключения уведомлений при отправке сообщений.
+ :param protect: Флаг защиты контента сообщений.
+
+ :return: Готовый шаблон для команды.
+ """
def __init__(self, name: str,
keywords: list,
func: Optional[list[Callable]] = None,
- text_msg=None,
+ text_msg = None,
chat_action: bool = False,
description: str = "Описание команды",
tg_links: bool = False,
@@ -34,15 +65,16 @@ class CommandHandler:
activate_commands: bool = True,
activate_callback: bool = True,
media: str = "message",
- path_to_media=None,
+ path_to_media = None,
parse_mode: str = BotVar.parse_mode,
disable_notification: bool = BotVar.disable_notification,
protect: bool = BotVar.protect_content):
+
self.router = Router(name=f"{name}_router")
self.name = name
self.log_type = name.capitalize()
self.description = description
- self.last_bot_message = {} # {chat_id: message_id}
+ self.last_bot_message = {}
self.keywords = keywords
self.text_msg = text_msg
@@ -125,7 +157,10 @@ class CommandHandler:
text = text.replace("", str(message.from_user.id))
Logs.info(log_type=self.log_type, user=username(message), text=f"использовал(а) команду /{self.name}")
- await base_sql(message)
+
+ # Работа с базами данных
+ db.update_user(message)
+ db.update_user_messages(message)
# Обрабатываем текстовое сообщение
if callable(self.text_msg):
diff --git a/BotLibrary/sql/__init__.py b/BotLibrary/sql/__init__.py
new file mode 100644
index 0000000..75eb74f
--- /dev/null
+++ b/BotLibrary/sql/__init__.py
@@ -0,0 +1,12 @@
+# BotLibrary/system/__init__.py
+# Инициализация пакета system, для библиотек запуска
+
+# Экспортирование модулей во внешние слои проекта
+from .db_class import *
+from ProjectsFiles import BotVar
+
+# Создание экземпляра класса
+db = Database(BotVar.bd_names)
+
+# Создание базы данных
+db.create_db()
diff --git a/BotLibrary/sql/db_class.py b/BotLibrary/sql/db_class.py
new file mode 100644
index 0000000..7d0de7f
--- /dev/null
+++ b/BotLibrary/sql/db_class.py
@@ -0,0 +1,563 @@
+# BotLibrary/system/db_class.py
+# Создание базы данных
+import os
+import sqlite3
+from datetime import datetime, timedelta, timezone
+from aiogram import types
+from typing import Optional, List, Tuple
+from ProjectsFiles import BotVar
+
+# Настройка экспорта в модули
+__all__ = ("Database",)
+
+class Database:
+ """Класс для управления базой данных пользователей чата с использованием SQLite3."""
+
+ def __init__(self, db_name: str = BotVar.bd_path) -> None:
+ """Инициализация класса с именем базы данных."""
+ self.db_name = db_name
+
+ # --- Основные методы из предоставленных функций ---
+
+ def create_db(self) -> None:
+ """Создание базы данных и таблиц с начальными данными."""
+ # Создание директории, если её нет
+ db_directory = os.path.dirname(self.db_name)
+ if db_directory and not os.path.exists(db_directory):
+ os.makedirs(db_directory)
+
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+
+ # Таблица пользователей
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS users (
+ user_id INTEGER PRIMARY KEY,
+ tg_id INTEGER NOT NULL UNIQUE,
+ username TEXT,
+ first_name TEXT,
+ last_name TEXT,
+ role TEXT DEFAULT NULL,
+ status TEXT DEFAULT 'active',
+ user TEXT DEFAULT 'user'
+ );''')
+
+ # Таблица сообщений пользователей
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS user_messages (
+ user_id INTEGER PRIMARY KEY,
+ last_message TEXT,
+ last_message_id INTEGER,
+ last_message_time TEXT,
+ messages_per_day INTEGER DEFAULT 0,
+ messages_per_week INTEGER DEFAULT 0,
+ messages_per_month INTEGER DEFAULT 0,
+ total_messages INTEGER DEFAULT 0,
+ FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE
+ );''')
+
+ # Таблица персонажей Genshin Impact
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS characters (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ region TEXT NOT NULL,
+ name TEXT NOT NULL,
+ status TEXT DEFAULT 'Свободно',
+ user_id INTEGER DEFAULT NULL,
+ comment TEXT DEFAULT '',
+ FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE SET NULL
+ );''')
+
+ # Таблица персонажей Honkai: Star Rail
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS characters_hsr (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ region TEXT NOT NULL,
+ name TEXT NOT NULL,
+ status TEXT DEFAULT 'Свободно',
+ user_id INTEGER DEFAULT NULL,
+ comment TEXT DEFAULT '',
+ FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE SET NULL
+ );''')
+
+ # Начальные данные для characters (Genshin Impact)
+ characters_genshin: list[tuple[str, str, str, str]] = [
+ # Мондштадт
+ ("Мондштадт", "Венти", "Свободно", ""),
+ ("Мондштадт", "Кэйа", "Свободно", ""),
+ ("Мондштадт", "Альбедо", "Свободно", ""),
+ ("Мондштадт", "Дилюк", "Свободно", ""),
+ ("Мондштадт", "Мика", "Свободно", ""),
+ ("Мондштадт", "Беннет", "Свободно", ""),
+ ("Мондштадт", "Рэйзор", "Свободно", ""),
+ ("Мондштадт", "Эола", "Свободно", ""),
+ ("Мондштадт", "Мона", "Свободно", ""),
+ ("Мондштадт", "Джинн", "Свободно", ""),
+ ("Мондштадт", "Диона", "Свободно", ""),
+ ("Мондштадт", "Лиза", "Свободно", ""),
+ ("Мондштадт", "Ноэлль", "Свободно", ""),
+ ("Мондштадт", "Сахароза", "Свободно", ""),
+ ("Мондштадт", "Розария", "Свободно", ""),
+ ("Мондштадт", "Эмбер", "Свободно", ""),
+ ("Мондштадт", "Фишль", "Свободно", ""),
+ ("Мондштадт", "Барбара", "Свободно", ""),
+
+ # Ли Юэ
+ ("Ли Юэ", "Чжун Ли", "Свободно", ""),
+ ("Ли Юэ", "Сяо", "Свободно", ""),
+ ("Ли Юэ", "Син Цю", "Свободно", ""),
+ ("Ли Юэ", "Чун Юнь", "Свободно", ""),
+ ("Ли Юэ", "Бай Чжу", "Свободно", ""),
+ ("Ли Юэ", "Е Лань", "Свободно", ""),
+ ("Ли Юэ", "Шень Хэ", "Свободно", ""),
+ ("Ли Юэ", "Гань Юй", "Свободно", ""),
+ ("Ли Юэ", "Ци Ци", "Свободно", ""),
+ ("Ли Юэ", "Кэ Цин", "Свободно", ""),
+ ("Ли Юэ", "Янь Фэй", "Свободно", ""),
+ ("Ли Юэ", "Нин Гуан", "Свободно", ""),
+ ("Ли Юэ", "Бэй Доу", "Свободно", ""),
+ ("Ли Юэ", "Яо Яо", "Свободно", ""),
+ ("Ли Юэ", "Ка Мин", "Свободно", ""),
+ ("Ли Юэ", "Сянь Юнь", "Свободно", ""),
+ ("Ли Юэ", "Юнь Цзинь", "Свободно", ""),
+ ("Ли Юэ", "Ху Тао", "Свободно", ""),
+ ("Ли Юэ", "Лань Янь", "Свободно", ""),
+
+ # Инадзума
+ ("Инадзума", "Итто", "Свободно", ""),
+ ("Инадзума", "Горо", "Свободно", ""),
+ ("Инадзума", "Аято", "Свободно", ""),
+ ("Инадзума", "Хэйдзо", "Свободно", ""),
+ ("Инадзума", "Тома", "Свободно", ""),
+ ("Инадзума", "Кадзуха", "Свободно", ""),
+ ("Инадзума", "Кирара", "Свободно", ""),
+ ("Инадзума", "Кудзё Сара", "Свободно", ""),
+ ("Инадзума", "Ёимия", "Свободно", ""),
+ ("Инадзума", "Аяка", "Свободно", ""),
+ ("Инадзума", "Сангономия Кокоми", "Свободно", ""),
+ ("Инадзума", "Яэ Мико", "Свободно", ""),
+ ("Инадзума", "Райдэн Эи", "Свободно", ""),
+ ("Инадзума", "Саю", "Свободно", ""),
+ ("Инадзума", "Куки Синобу", "Свободно", ""),
+ ("Инадзума", "Мидзуки", "Свободно", ""),
+
+ # Сумеру
+ ("Сумеру", "Аль-Хайтам", "Свободно", ""),
+ ("Сумеру", "Кавех", "Свободно", ""),
+ ("Сумеру", "Сайно", "Свободно", ""),
+ ("Сумеру", "Тигнари", "Свободно", ""),
+ ("Сумеру", "Сетос", "Свободно", ""),
+ ("Сумеру", "Нилу", "Свободно", ""),
+ ("Сумеру", "Нахида", "Свободно", ""),
+ ("Сумеру", "Лайла", "Свободно", ""),
+ ("Сумеру", "Кандакия", "Свободно", ""),
+ ("Сумеру", "Дори", "Свободно", ""),
+ ("Сумеру", "Дэхья", "Свободно", ""),
+ ("Сумеру", "Коллеи", "Свободно", ""),
+ ("Сумеру", "Фарузан", "Свободно", ""),
+
+ # Фонтейн
+ ("Фонтейн", "Лини", "Свободно", ""),
+ ("Фонтейн", "Ризли", "Свободно", ""),
+ ("Фонтейн", "Невиллет", "Свободно", ""),
+ ("Фонтейн", "Фремине", "Свободно", ""),
+ ("Фонтейн", "Линетт", "Свободно", ""),
+ ("Фонтейн", "Эмилия", "Свободно", ""),
+ ("Фонтейн", "Клоринда", "Свободно", ""),
+ ("Фонтейн", "Навия", "Свободно", ""),
+ ("Фонтейн", "Шарлотта", "Свободно", ""),
+ ("Фонтейн", "Фурина", "Свободно", ""),
+ ("Фонтейн", "Тиори", "Свободно", ""),
+ ("Фонтейн", "Сиджвин", "Свободно", ""),
+
+ # Натлан
+ ("Натлан", "Кинич", "Свободно", ""),
+ ("Натлан", "Оророн", "Свободно", ""),
+ ("Натлан", "Муалани", "Свободно", ""),
+ ("Натлан", "Ситлали", "Свободно", ""),
+ ("Натлан", "Шилонен", "Свободно", ""),
+ ("Натлан", "Иансан", "Свободно", ""),
+ ("Натлан", "Мавуика", "Свободно", ""),
+ ("Натлан", "Часка", "Свободно", ""),
+
+ # Фатуи
+ ("Фатуи", "Тарталья", "Свободно", ""),
+ ("Фатуи", "Панталоне", "Свободно", ""),
+ ("Фатуи", "Дотторе", "Свободно", ""),
+ ("Фатуи", "Капитано", "Свободно", ""),
+ ("Фатуи", "Пьеро", "Свободно", ""),
+ ("Фатуи", "Пульничелла", "Свободно", ""),
+ ("Фатуи", "Синьора", "Свободно", ""),
+ ("Фатуи", "Арлекино", "Свободно", ""),
+ ("Фатуи", "Коломбина", "Свободно", ""),
+ ("Фатуи", "Царица", "Свободно", ""),
+ ("Фатуи", "Странник", "Свободно", ""),
+
+ # Иные персонажи
+ ("Иные персонажи", "Итэр", "Свободно", ""),
+ ("Иные персонажи", "Люмин", "Свободно", ""),
+ ("Иные персонажи", "Элой", "Свободно", ""),
+ ("Иные персонажи", "Паймон", "Свободно", ""),
+ ("Иные персонажи", "Дайнслейф", "Свободно", ""),
+ ]
+
+ # Начальные данные для characters_hsr (Honkai: Star Rail)
+ characters_hsr: list[tuple[str, str, str, str]] = [
+ # Ярило-6
+ ("Ярило-6", "Броня", "Свободно", ""),
+ ("Ярило-6", "Гепард", "Свободно", ""),
+ ("Ярило-6", "Зеле", "Свободно", ""),
+ ("Ярило-6", "Клара", "Свободно", ""),
+ ("Ярило-6", "Лука", "Свободно", ""),
+ ("Ярило-6", "Наташа", "Свободно", ""),
+ ("Ярило-6", "Пела", "Свободно", ""),
+ ("Ярило-6", "Рысь", "Свободно", ""),
+ ("Ярило-6", "Сампо", "Свободно", ""),
+ ("Ярило-6", "Сервал", "Свободно", ""),
+ ("Ярило-6", "Хук", "Свободно", ""),
+
+ # Станция «Герта»
+ ("Станция «Герта»", "Арлан", "Свободно", ""),
+ ("Станция «Герта»", "Аста", "Свободно", ""),
+ ("Станция «Герта»", "Великая Герта", "Свободно", ""),
+ ("Станция «Герта»", "Кукла «Герта»", "Свободно", ""),
+ ("Станция «Герта»", "Жуань Мэй", "Свободно", ""),
+
+ # Пенакония
+ ("Пенакония", "Авантюрин", "Свободно", ""),
+ ("Пенакония", "Ахерон", "Свободно", ""),
+ ("Пенакония", "Галлахер", "Свободно", ""),
+ ("Пенакония", "Зарянка", "Свободно", ""),
+ ("Пенакония", "Миша", "Свободно", ""),
+ ("Пенакония", "Мистер Река", "Свободно", ""),
+ ("Пенакония", "Раппа", "Свободно", ""),
+ ("Пенакония", "Чёрный Лебедь", "Свободно", ""),
+ ("Пенакония", "Яшма", "Свободно", ""),
+ ("Пенакония", "Воскресенье", "Свободно", ""),
+
+ # Звёздный Экспресс
+ ("Звёздный Экспресс", "Вельт", "Свободно", ""),
+ ("Звёздный Экспресс", "Келус", "Свободно", ""),
+ ("Звёздный Экспресс", "Стелла", "Свободно", ""),
+ ("Звёздный Экспресс", "Дань Хэн", "Свободно", ""),
+ ("Звёздный Экспресс", "Март 7", "Свободно", ""),
+ ("Звёздный Экспресс", "Химеко", "Свободно", ""),
+ ("Звёздный Экспресс", "Пом Пом", "Свободно", ""),
+
+ # Галактика
+ ("Галактика", "Аргенти", "Свободно", ""),
+ ("Галактика", "Блэйд", "Свободно", ""),
+ ("Галактика", "Бутхилл", "Свободно", ""),
+ ("Галактика", "Доктор Рацио", "Свободно", ""),
+ ("Галактика", "Кафка", "Свободно", ""),
+ ("Галактика", "Светлячок", "Свободно", ""),
+ ("Галактика", "Искорка", "Свободно", ""),
+ ("Галактика", "Серебряный Волк", "Свободно", ""),
+ ("Галактика", "Топаз", "Свободно", ""),
+
+ # Амфореус
+ ("Амфореус", "Аглая", "Свободно", ""),
+ ("Амфореус", "Мидей", "Свободно", ""),
+ ("Амфореус", "Трибби", "Свободно", ""),
+
+ # Альянс Сяньчжоу
+ ("Альянс Сяньчжоу", "Байлу", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Гуйнайфей", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Линша", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Лоча", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Моцзэ", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Пожиратель Луны", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Сушан", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Сюзи", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Фуга", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Фэйсяо", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Ханья", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Хохо", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Цзин Юань", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Цзиннлю", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Цзяоцю", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Цинцюэ", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Юйкун", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Юньли", "Свободно", ""),
+ ("Альянс Сяньчжоу", "Яньцин", "Свободно", ""),
+ ]
+
+ # Заполнение таблиц начальными данными, если они пусты
+ cursor.execute("SELECT COUNT(*) FROM characters")
+ if cursor.fetchone()[0] == 0:
+ cursor.executemany('INSERT INTO characters (region, name, status, comment) VALUES (?, ?, ?, ?)',
+ characters_genshin)
+
+ cursor.execute("SELECT COUNT(*) FROM characters_hsr")
+ if cursor.fetchone()[0] == 0:
+ cursor.executemany('INSERT INTO characters_hsr (region, name, status, comment) VALUES (?, ?, ?, ?)',
+ characters_hsr)
+
+ db.commit()
+
+ def add_user(self, tg_id: int, username: str, first_name: str, last_name: str, role: str, status: str,
+ user: str) -> None:
+ """Добавление нового пользователя в базу данных."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+
+ # Проверка на существование пользователя
+ cursor.execute("SELECT user_id FROM users WHERE tg_id = ?", (tg_id,))
+ if cursor.fetchone():
+ return # Пользователь уже существует
+
+ # Определение нового user_id
+ cursor.execute("SELECT MAX(user_id) FROM users")
+ max_id = cursor.fetchone()[0]
+ new_user_id = 1 if max_id is None else max_id + 1
+
+ # Вставка пользователя
+ cursor.execute('''
+ INSERT INTO users (user_id, tg_id, username, first_name, last_name, role, status, user)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ ''', (new_user_id, tg_id, username, first_name, last_name, role, status, user))
+
+ # Создание записи в user_messages
+ cursor.execute('INSERT INTO user_messages (user_id) VALUES (?)', (new_user_id,))
+ db.commit()
+
+ def get_user(self, tg_id: int) -> Optional[Tuple]:
+ """Получение информации о пользователе по tg_id."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute("SELECT * FROM users WHERE tg_id = ?", (tg_id,))
+ return cursor.fetchone()
+
+ def update_user(self, tg_id: int, username: Optional[str] = None, first_name: Optional[str] = None,
+ last_name: Optional[str] = None, role: Optional[str] = None, user: Optional[str] = None) -> None:
+ """Обновление данных о пользователе."""
+ updates = []
+ params = []
+
+ if username:
+ updates.append("username = ?")
+ params.append(username)
+ if first_name:
+ updates.append("first_name = ?")
+ params.append(first_name)
+ if last_name:
+ updates.append("last_name = ?")
+ params.append(last_name)
+ if role:
+ updates.append("role = ?")
+ params.append(role)
+ if user:
+ updates.append("user = ?")
+ params.append(user)
+
+ if updates:
+ query = f"UPDATE users SET {', '.join(updates)} WHERE tg_id = ?"
+ params.append(tg_id)
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute(query, params)
+ db.commit()
+
+ def update_user_messages(self, message: types.Message) -> None:
+ """Обновление статистики сообщений пользователя."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ tg_id = message.from_user.id
+
+ # Получение user_id
+ cursor.execute("SELECT user_id FROM users WHERE tg_id = ?", (tg_id,))
+ result = cursor.fetchone()
+ if not result:
+ return # Пользователь не найден
+ user_id = result[0]
+
+ # Проверка существующей записи в user_messages
+ cursor.execute(
+ "SELECT last_message_time, messages_per_day, messages_per_week, messages_per_month, total_messages "
+ "FROM user_messages WHERE user_id = ?", (user_id,))
+ result = cursor.fetchone()
+
+ # Время сообщения в московском часовом поясе
+ now = message.date.astimezone(timezone(timedelta(hours=3)))
+ today = now.date()
+ start_of_week = today - timedelta(days=today.weekday())
+ current_month = now.month
+ current_year = now.year
+
+ last_message = message.text or "Н/Д" # Замените на type_msg(message) при необходимости
+ last_message_id = message.message_id
+
+ if result:
+ last_message_time, messages_per_day, messages_per_week, messages_per_month, total_messages = result
+ if last_message_time:
+ last_message_time = datetime.fromisoformat(last_message_time).astimezone(
+ timezone(timedelta(hours=3)))
+ last_date = last_message_time.date()
+ last_week = last_date - timedelta(days=last_date.weekday())
+ last_month = last_message_time.month
+ last_year = last_message_time.year
+
+ # Обнуление счетчиков при смене периода
+ if last_date != today:
+ messages_per_day = 0
+ if last_week != start_of_week:
+ messages_per_week = 0
+ if last_month != current_month or last_year != current_year:
+ messages_per_month = 0
+ else:
+ messages_per_day, messages_per_week, messages_per_month = 0, 0, 0
+
+ # Увеличение счетчиков
+ messages_per_day += 1
+ messages_per_week += 1
+ messages_per_month += 1
+ total_messages += 1
+ else:
+ messages_per_day, messages_per_week, messages_per_month, total_messages = 1, 1, 1, 1
+ cursor.execute('''
+ INSERT INTO user_messages (user_id, last_message, last_message_id, last_message_time,
+ messages_per_day, messages_per_week, messages_per_month, total_messages)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ ''', (user_id, last_message, last_message_id, now.isoformat(), messages_per_day,
+ messages_per_week, messages_per_month, total_messages))
+ db.commit()
+ return
+
+ # Обновление записи
+ cursor.execute('''
+ UPDATE user_messages
+ SET last_message = ?, last_message_id = ?, last_message_time = ?,
+ messages_per_day = ?, messages_per_week = ?, messages_per_month = ?,
+ total_messages = ?
+ WHERE user_id = ?
+ ''', (last_message, last_message_id, now.isoformat(), messages_per_day,
+ messages_per_week, messages_per_month, total_messages, user_id))
+ db.commit()
+
+ def get_user_status(self, message: types.Message) -> str:
+ """Получение статуса пользователя."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute("SELECT user FROM users WHERE tg_id = ?", (message.from_user.id,))
+ row = cursor.fetchone()
+ status_map = {
+ "ban": "Забанен",
+ "user": "Пользователь",
+ "moderator": "Модератор",
+ "admin": "Администратор",
+ "so-owner": "Совладелец",
+ "owner": "Владелец",
+ }
+ return status_map.get(row[0], "Ошибка!") if row else "Пользователь не найден"
+
+ # --- Новые и улучшенные методы ---
+
+ def delete_user(self, tg_id: int) -> None:
+ """Удаление пользователя из базы данных."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute("DELETE FROM users WHERE tg_id = ?", (tg_id,))
+ db.commit()
+
+ def get_all_users(self) -> List[Tuple]:
+ """Получение списка всех пользователей."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute("SELECT * FROM users")
+ return cursor.fetchall()
+
+ def get_user_messages(self, tg_id: int) -> Optional[Tuple]:
+ """Получение статистики сообщений пользователя."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute("SELECT user_id FROM users WHERE tg_id = ?", (tg_id,))
+ result = cursor.fetchone()
+ if not result:
+ return None
+ user_id = result[0]
+ cursor.execute("SELECT * FROM user_messages WHERE user_id = ?", (user_id,))
+ return cursor.fetchone()
+
+ def ban_user(self, tg_id: int) -> None:
+ """Блокировка пользователя."""
+ self.update_user(tg_id, user="ban")
+
+ def unban_user(self, tg_id: int) -> None:
+ """Разблокировка пользователя."""
+ self.update_user(tg_id, user="user")
+
+ def promote_user(self, tg_id: int, new_role: str) -> None:
+ """Изменение роли пользователя."""
+ valid_roles = ["user", "moderator", "admin", "so-owner", "owner"]
+ if new_role in valid_roles:
+ self.update_user(tg_id, user=new_role)
+
+ def get_top_active_users(self, limit: int = 10) -> List[Tuple]:
+ """Получение самых активных пользователей по количеству сообщений."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute('''
+ SELECT u.tg_id, u.username, um.total_messages
+ FROM users u
+ JOIN user_messages um ON u.user_id = um.user_id
+ ORDER BY um.total_messages DESC
+ LIMIT ?
+ ''', (limit,))
+ return cursor.fetchall()
+
+ def assign_character(self, tg_id: int, character_id: int, game: str = "genshin") -> bool:
+ """Назначение персонажа пользователю."""
+ table = "characters" if game == "genshin" else "characters_hsr"
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute(f"SELECT user_id FROM {table} WHERE id = ?", (character_id,))
+ result = cursor.fetchone()
+ if result and result[0] is not None:
+ return False # Персонаж уже занят
+
+ cursor.execute("SELECT user_id FROM users WHERE tg_id = ?", (tg_id,))
+ user_id = cursor.fetchone()
+ if not user_id:
+ return False # Пользователь не найден
+
+ cursor.execute(f"UPDATE {table} SET user_id = ?, status = 'Занят' WHERE id = ?", (user_id[0], character_id))
+ db.commit()
+ return True
+
+ def free_character(self, character_id: int, game: str = "genshin") -> None:
+ """Освобождение персонажа."""
+ table = "characters" if game == "genshin" else "characters_hsr"
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute(f"UPDATE {table} SET user_id = NULL, status = 'Свободно' WHERE id = ?", (character_id,))
+ db.commit()
+
+ def get_user_characters(self, tg_id: int, game: str = "genshin") -> List[Tuple]:
+ """Получение списка персонажей пользователя."""
+ table = "characters" if game == "genshin" else "characters_hsr"
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute("SELECT user_id FROM users WHERE tg_id = ?", (tg_id,))
+ user_id = cursor.fetchone()
+ if not user_id:
+ return []
+ cursor.execute(f"SELECT * FROM {table} WHERE user_id = ?", (user_id[0],))
+ return cursor.fetchall()
+
+ def search_users(self, query: str) -> List[Tuple]:
+ """Поиск пользователей по имени или юзернейму."""
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute("""
+ SELECT * FROM users
+ WHERE username LIKE ? OR first_name LIKE ? OR last_name LIKE ?
+ """, (f"%{query}%", f"%{query}%", f"%{query}%"))
+ return cursor.fetchall()
+
+ def get_character_by_name(self, name: str, game: str = "genshin") -> Optional[Tuple]:
+ """Поиск персонажа по имени."""
+ table = "characters" if game == "genshin" else "characters_hsr"
+ with sqlite3.connect(self.db_name) as db:
+ cursor = db.cursor()
+ cursor.execute(f"SELECT * FROM {table} WHERE name = ?", (name,))
+ return cursor.fetchone()
diff --git a/BotLibrary/system/bot_edit.py b/BotLibrary/system/bot_edit.py
index 9553b5d..1ad9c49 100644
--- a/BotLibrary/system/bot_edit.py
+++ b/BotLibrary/system/bot_edit.py
@@ -1,153 +1,115 @@
# BotLibrary/system/bot_edit.py
# Под-пакет установки настроек бота
-from aiogram.types import ChatAdministratorRights
+from aiogram import Bot
from ProjectsFiles import BotEdit
-from .bots import bot
-
-# Настройка логирования
-log_type = "Edit"
# Настройка экспорта из модуля
-__all__ = ("set_adm_rights", "set_bot_name", "set_bot_description", "set_bot_short_description")
+__all__ = ("BotRights",)
-# Функция установки прав администратора
-async def set_adm_rights(anonym: bool = BotEdit.is_anonymous,
- manage_chat: bool = BotEdit.manage_chat,
- delete_msg: bool = BotEdit.delete_messages,
- manage_video_chats: bool = BotEdit.manage_video_chats,
- restrict_members: bool = BotEdit.restrict_members,
- promote_members: bool = BotEdit.promote_members,
- change_info: bool = BotEdit.change_info,
- invite_users: bool = BotEdit.invite_users,
- post_stories: bool = BotEdit.post_stories,
- edit_stories: bool = BotEdit.edit_stories,
- delete_stories: bool = BotEdit.delete_stories,
- post_messages: bool = BotEdit.post_messages,
- edit_messages: bool = BotEdit.edit_messages,
- pin_messages: bool = BotEdit.pin_messages,
- manage_topics: bool = BotEdit.manage_topics,) -> None:
+class BotRights:
"""
- Устанавливает права администратора для бота, если они отличаются от текущих.
- Все через конфиги!!!
-
- :param anonym: Позволяет ли боту быть анонимным.
- :param manage_chat: Разрешение на управление чатом.
- :param delete_msg: Разрешение на удаление сообщений.
- :param manage_video_chats: Разрешение на управление видеочатами.
- :param restrict_members: Разрешение на ограничение участников (мут, бан).
- :param promote_members: Разрешение на назначение администраторов.
- :param change_info: Разрешение на изменение информации о группе/канале.
- :param invite_users: Разрешение на приглашение новых участников.
- :param post_stories: Разрешение на публикацию историй.
- :param edit_stories: Разрешение на редактирование историй.
- :param delete_stories: Разрешение на удаление историй.
- :param post_messages: Разрешение на публикацию сообщений (только для каналов).
- :param edit_messages: Разрешение на редактирование сообщений (только для каналов).
- :param pin_messages: Разрешение на закрепление сообщений.
- :param manage_topics: Разрешение на управление темами (в супергруппах).
-
- :return: Изменение прав администратора
+ Класс для установки прав администратора и метаинформации бота (имя, описания).
"""
- rights = ChatAdministratorRights(
- is_anonymous=anonym,
- can_manage_chat=manage_chat,
- can_delete_messages=delete_msg,
- can_manage_video_chats=manage_video_chats,
- can_restrict_members=restrict_members,
- can_promote_members=promote_members,
- can_change_info=change_info,
- can_invite_users=invite_users,
- can_post_stories=post_stories,
- can_edit_stories=edit_stories,
- can_delete_stories=delete_stories,
- can_post_messages=post_messages,
- can_edit_messages=edit_messages,
- can_pin_messages=pin_messages,
- can_manage_topics=manage_topics,
- )
+ @staticmethod
+ async def set_administrator_rights(bot: Bot) -> None:
+ """
+ Установка прав администратора в чатах.
- # Применяем права только в случае изменения
- current_rights = await bot.get_my_default_administrator_rights()
- if current_rights != rights:
- await bot.set_my_default_administrator_rights(rights)
- else:
- return
+ :param bot: Базовый объект бота.
+ :return: Измененные права по конфигу.
+ """
+ from aiogram.types import ChatAdministratorRights
+ rights: ChatAdministratorRights = ChatAdministratorRights(
+ is_anonymous=BotEdit.is_anonymous,
+ can_manage_chat=BotEdit.manage_chat,
+ can_delete_messages=BotEdit.delete_messages,
+ can_manage_video_chats=BotEdit.manage_video_chats,
+ can_restrict_members=BotEdit.restrict_members,
+ can_promote_members=BotEdit.promote_members,
+ can_change_info=BotEdit.change_info,
+ can_invite_users=BotEdit.invite_users,
+ can_post_stories=BotEdit.post_stories,
+ can_edit_stories=BotEdit.edit_stories,
+ can_delete_stories=BotEdit.delete_stories,
+ can_post_messages=BotEdit.post_messages,
+ can_edit_messages=BotEdit.edit_messages,
+ can_pin_messages=BotEdit.pin_messages,
+ can_manage_topics=BotEdit.manage_topics,
+ )
+ current_rights: ChatAdministratorRights = await bot.get_my_default_administrator_rights()
+ if current_rights != rights:
+ await bot.set_my_default_administrator_rights(rights)
-# Функция установки имени бота с проверкой на ограничения
-async def set_bot_name(new_name: str = BotEdit.name) -> None:
- """
- Устанавливает имя бота, если оно отличается от текущего и соответствует ограничениям.
+ @staticmethod
+ async def set_name(bot: Bot) -> None:
+ """
+ Установка имени бота.
- :param new_name: Новое имя бота (config)
- :return: Имя бота
- """
- # Импортируем Logs внутри функции, чтобы избежать циклического импорта
- from ..loggers.custom_loggers import Logs
+ :param bot: Базовый объект бота.
+ :return: Измененное имя бота.
+ """
+ current_name: str = (await bot.get_me()).first_name
+ new_name: str = str(BotEdit.name)
- # Получаем текущее имя бота
- current_name = (await bot.get_me()).first_name
+ if not (1 <= len(new_name) <= 32):
+ from ..loggers import Logs
+ Logs.error(log_type="SET_NAME", user="BOT", text="Имя бота должно быть от 1 до 32 символов.")
+ return
- # Проверка длины имени
- 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 != new_name:
+ await bot.set_my_name(new_name)
- # Проверяем, совпадает ли текущее имя с тем, которое мы хотим установить
- if current_name != new_name:
- await bot.set_my_name(new_name)
- else:
- return
+ @staticmethod
+ async def set_description(bot: Bot) -> None:
+ """
+ Установка описания бота.
+ :param bot: Базовый объект бота.
+ :return: Измененное описание бота.
+ """
+ from aiogram.types import BotDescription
+ current_description: BotDescription = await bot.get_my_description()
+ new_description: str = str(BotEdit.description)
-# Функция установки описания бота с проверкой на ограничения
-async def set_bot_description(new_description: str = BotEdit.description) -> None:
- """
- Устанавливает описание бота, если оно отличается от текущего и соответствует ограничениям.
+ if not (0 < len(new_description) <= 255):
+ from ..loggers import Logs
+ Logs.error(log_type="SET_DESCRIPTION", user="BOT", text="Описание должно быть от 1 до 255 символов.")
+ return
- :param new_description: Новое описание для бота (config)
- :return: Описание бота
- """
- # Импортируем Logs внутри функции, чтобы избежать циклического импорта
- from ..loggers.custom_loggers import Logs
+ if current_description != new_description:
+ await bot.set_my_description(description=new_description)
- # Получаем текущее описание бота
- current_description = await bot.get_my_description()
+ @staticmethod
+ async def set_short_description(bot: Bot) -> None:
+ """
+ Установка описания виджета.
- # Проверка длины описания
- if len(new_description) > 255 or len(new_description)==0:
- Logs.error(log_type=log_type, user="DISCRIPT", text="Короткое описание бота не может превышать 255 символов или быть равно 0.")
- return # Выходим из функции, если описание некорректно
+ :param bot: Базовый объект бота.
+ :return: Измененное описание виджета бота.
+ """
+ from aiogram.types import BotShortDescription
+ current_short_description: BotShortDescription = await bot.get_my_short_description()
+ new_short_description: str = str(BotEdit.short_description)
- # Проверяем, совпадает ли текущее описание с тем, которое мы хотим установить
- if current_description != new_description:
- await bot.set_my_description(description=new_description)
- else:
- return
+ if not (0 < len(new_short_description) <= 512):
+ from ..loggers import Logs
+ Logs.error(log_type="SET_SHORT_DESCRIPTION", user="BOT", text="Короткое описание должно быть от 1 до 512 символов.")
+ return
+ if current_short_description != new_short_description:
+ await bot.set_my_short_description(short_description=new_short_description)
-# Функция установки короткого описания бота с проверкой на ограничения
-async def set_bot_short_description(new_short_description: str = BotEdit.short_description) -> None:
- """
- Устанавливает короткое описание бота, если оно отличается от текущего и соответствует ограничениям.
+ @staticmethod
+ async def all(bot: Bot) -> 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(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 != new_short_description:
- await bot.set_my_short_description(short_description=new_short_description)
- else:
- return
+ :param bot: Базовый объект бота.
+ :return: Изменение всех основных параметров бота.
+ """
+ await BotRights.set_administrator_rights(bot)
+ await BotRights.set_name(bot)
+ await BotRights.set_description(bot)
+ await BotRights.set_short_description(bot)
diff --git a/BotLibrary/system/bots.py b/BotLibrary/system/bots.py
index a377419..bf90244 100644
--- a/BotLibrary/system/bots.py
+++ b/BotLibrary/system/bots.py
@@ -17,23 +17,14 @@ dp = Dispatcher()
dp["started_at"] = get_host_time()
dp["started_at_city"] = get_city_time()
dp["is_active"] = True # Флаг активности бота
-dp["logs"] = []
-dp["users"] = {}
-dp["admins"] = {}
-dp["sessions"] = {}
-dp["task_queue"] = []
dp["configs"] = {"max_connections": 100, "retry_interval": 5, "time_format": BotVar.time_format}
dp["metrics"] = {"messages_received": 0, "messages_sent": 0, "errors": 0}
-dp["modules"] = {}
-dp["state"] = {}
-dp["scheduler"] = []
dp["handlers"] = {"on_message": [], "on_error": []}
-dp["storage"] = {}
dp["database"] = "SQLite3"
# Создание экземпляра бота и его настройка
-bot = Bot(token=bot_token, default=DefaultBotProperties(
+bot: Bot = Bot(token=bot_token, default=DefaultBotProperties(
parse_mode=BotVar.parse_mode,
disable_notification=BotVar.disable_notification,
protect_content=BotVar.protect_content,
@@ -57,27 +48,31 @@ class BotInfo:
"""
id: int = None
first_name: str = None
- bot_owner: str = BotVar
last_name: str = None
username: str = None
- description: str = None
- short_description: str = None
- can_join_groups: bool = False
- can_read_all_group_messages: bool = False
+ description: str = ''
+ short_description: str = ''
language_code: str = BotVar.language
prefix: str = BotVar.prefix
+ bot_owner: str = BotVar
is_premium: bool = False
added_to_attachment_menu: bool = False
supports_inline_queries: bool = False
can_connect_to_business: bool = False
has_main_web_app: bool = False
+ can_join_groups: bool = False
+ can_read_all_group_messages: bool = False
@classmethod
- def update(cls, bot_info) -> None:
+ async def info(cls, bots: Bot = bot) -> dict:
"""
- Обновляет данные о боте.
- :param bot_info: Объект с данными о боте, полученные через API Telegram.
+ Получает информацию о боте через API и обновляет данные в классе.
+
+ :param bots: Объект бота
+ :return: Словарь с данными о боте
"""
+ bot_info = await bots.get_me()
+
cls.id = bot_info.id
cls.first_name = bot_info.first_name
cls.last_name = bot_info.last_name
@@ -93,31 +88,28 @@ class BotInfo:
cls.can_join_groups = getattr(bot_info, 'can_join_groups', False)
cls.can_read_all_group_messages = getattr(bot_info, 'can_read_all_group_messages', False)
+ return cls.to_dict()
-# Функция получения информации о боте
-async def bot_get_info(bots: Bot = bot) -> dict:
- """
- Получает информацию о боте и обновляет данные в классе BotInfo.
- :param bots: Получение объекта бота в функцию.
- :return: Словарь с данными о боте.
- """
- bot_info_data = await bots.get_me()
- BotInfo.update(bot_info_data)
- return {
- 'bot_info': bot_info_data,
- 'id': bot_info_data.id,
- 'first_name': bot_info_data.first_name,
- 'last_name': bot_info_data.last_name,
- 'username': bot_info_data.username,
- 'description': getattr(bot_info_data, 'description', ''),
- 'short_description': getattr(bot_info_data, 'short_description', ''),
- 'language_code': bot_info_data.language_code,
- 'prefix': BotVar.prefix,
- 'is_premium': bot_info_data.is_premium,
- 'added_to_attachment_menu': bot_info_data.added_to_attachment_menu,
- 'supports_inline_queries': bot_info_data.supports_inline_queries,
- 'can_connect_to_business': bot_info_data.can_connect_to_business,
- 'has_main_web_app': bot_info_data.has_main_web_app,
- 'can_join_groups': getattr(bot_info_data, 'can_join_groups', False),
- 'can_read_all_group_messages': getattr(bot_info_data, 'can_read_all_group_messages', False),
- }
+ @classmethod
+ def to_dict(cls) -> dict:
+ """
+ Возвращает текущие данные в виде словаря.
+ """
+ return {
+ 'id': cls.id,
+ 'first_name': cls.first_name,
+ 'last_name': cls.last_name,
+ 'username': cls.username,
+ 'description': cls.description,
+ 'short_description': cls.short_description,
+ 'language_code': cls.language_code,
+ 'prefix': cls.prefix,
+ 'bot_owner': cls.bot_owner,
+ 'is_premium': cls.is_premium,
+ 'added_to_attachment_menu': cls.added_to_attachment_menu,
+ 'supports_inline_queries': cls.supports_inline_queries,
+ 'can_connect_to_business': cls.can_connect_to_business,
+ 'has_main_web_app': cls.has_main_web_app,
+ 'can_join_groups': cls.can_join_groups,
+ 'can_read_all_group_messages': cls.can_read_all_group_messages,
+ }
diff --git a/BotLibrary/system/directory.py b/BotLibrary/system/directory.py
index 89621e5..c582110 100644
--- a/BotLibrary/system/directory.py
+++ b/BotLibrary/system/directory.py
@@ -2,51 +2,47 @@
# Создание пустых директорий при первом запуске
import os
-from ProjectsFiles import ProjectPath, TypeDirectory
from typing import List
+from ProjectsFiles import ProjectPath, TypeDirectory
# Настройка экспорта из модуля
-__all__ = ("create_directories", "setup_directories", "create_directory")
+__all__ = ("Directory",)
+class Directory:
+ @staticmethod
+ async def create_directory(directory: str) -> None:
+ """
+ Создает директории, если они еще не существуют.
-# Функция создания директории
-async def create_directory(directory : str) -> None:
- """
- Создает директории, если они еще не существуют.
+ :param directory: Путь к базовой директории.
+ :return: Создание директорий по определенному пути.
+ """
+ os.makedirs(directory, exist_ok=True)
- :param directory: Путь к базовой директории.
- :return: Создание директорий по определенному пути.
- """
- os.makedirs(directory)
+ @staticmethod
+ async def create_directories(base_directory: str, subdirectories: List[str]) -> None:
+ """
+ Создает указанные поддиректории в указанной базовой директории.
+ :param base_directory: Путь к базовой директории.
+ :param subdirectories: Список поддиректорий, которые необходимо создать.
+ :return: Создание директорий по определенному пути.
+ """
+ # Создание директорий и файлов в каждой из них
+ for subdirectory in subdirectories:
+ directory_path = os.path.join(base_directory, subdirectory)
-# Функция создания поддиректорий
-async def create_directories(base_directory: str, subdirectories: List[str]) -> None:
- """
- Создает указанные поддиректории в указанной базовой директории.
+ # Проверка, существует ли директория, если нет - создаём
+ os.makedirs(directory_path, exist_ok=True)
- :param base_directory: Путь к базовой директории.
- :param subdirectories: Список поддиректорий, которые необходимо создать.
- :return: Создание директорий по определенному пути.
- """
- # Создание директорий и файлов в каждой из них
- for subdirectory in subdirectories:
- directory_path = os.path.join(base_directory, subdirectory)
+ @staticmethod
+ async def setup() -> None:
+ """
+ Настройка начальных пустых директорий для проекта.
- # Проверка, существует ли директория, если нет - создаём
- if not os.path.exists(directory_path):
- os.makedirs(directory_path)
-
-
-# Функция установки начальных директорий
-async def setup_directories() -> None:
- """
- Настройка начальных пустых директорий для проекта.
-
- :return: Создание системы директорий по определенному пути.
- """
- # Создание директорий для медиа файлов
- await create_directories(ProjectPath.personal_media, TypeDirectory.media_directories)
- await create_directories(ProjectPath.received_media, TypeDirectory.media_directories)
- await create_directories(ProjectPath.received_avatars, TypeDirectory.avatar_directories)
- # await create_directories(ProjectPath.msg, TypeDirectory.msg_directories)
+ :return: Создание системы директорий по определенному пути.
+ """
+ # Создание директорий для медиа файлов
+ await Directory.create_directories(ProjectPath.personal_media, TypeDirectory.media_directories)
+ await Directory.create_directories(ProjectPath.received_media, TypeDirectory.media_directories)
+ await Directory.create_directories(ProjectPath.received_avatars, TypeDirectory.avatar_directories)
diff --git a/BotLibrary/timer/start_time.py b/BotLibrary/timer/start_time.py
index 75c05cd..9ff9626 100644
--- a/BotLibrary/timer/start_time.py
+++ b/BotLibrary/timer/start_time.py
@@ -1,7 +1,6 @@
# BotLibrary/timer/start_time.py
# Получение времени по разным часовым поясам
-import pytz
from datetime import datetime
from tzlocal import get_localzone
from apscheduler.schedulers.asyncio import AsyncIOScheduler
@@ -14,7 +13,6 @@ __all__ = ("scheduler", "get_city_time", "get_host_time")
scheduler = AsyncIOScheduler(timezone=get_localzone().key)
-# Функция получение иного времени
def get_city_time(city: str = 'Europe/Moscow',
time_format: str = BotVar.time_format) -> str:
"""
@@ -24,13 +22,13 @@ def get_city_time(city: str = 'Europe/Moscow',
:param time_format: Шаблон форматирования времени (конфиг).
:return: Строка, представляющая время в формате, заданном в BotVar.time_format.
"""
+ from pytz import timezone
# Устанавливаем временную зону для Москвы
- city_tz = pytz.timezone(city)
+ city_tz = timezone(city)
# Возвращаем строку с форматом времени
return datetime.now(city_tz).strftime(time_format)
-# Функция получение времени хоста
def get_host_time(time_format: str = BotVar.time_format) -> str:
"""
Получение текущего времени хоста (локального времени).
diff --git a/BotLibrary/validators/email_valid.py b/BotLibrary/validators/email_valid.py
index 9782d30..2d4bd8f 100644
--- a/BotLibrary/validators/email_valid.py
+++ b/BotLibrary/validators/email_valid.py
@@ -2,13 +2,10 @@
# Создание валидации почты для проекта
from typing import Optional
-from email_validator import validate_email, EmailNotValidError
# Настройка экспорта из этого модуля
__all__ = ("valid_email",)
-
-# Функция проверки почты на корректность
def valid_email(email: str) -> Optional[str]:
"""
Делает почтовый адрес корректным.
@@ -16,10 +13,12 @@ def valid_email(email: str) -> Optional[str]:
:param email: Почтовый адрес в виде строки.
:return: Нормализованный почтовый адрес, если он валиден, иначе None.
"""
+ from email_validator import validate_email, EmailNotValidError
try:
return validate_email(email).normalized
+
except EmailNotValidError as e:
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
- from ..loggers.custom_loggers import Logs
+ from ..loggers.logs import Logs
Logs.error(text=f"Ошибка в нормализировании почты: {e}", log_type="NormalEmail")
- return None
\ No newline at end of file
+ return None
diff --git a/BotLibrary/validators/normal_word.py b/BotLibrary/validators/normal_word.py
index ab122cf..62ad0ef 100644
--- a/BotLibrary/validators/normal_word.py
+++ b/BotLibrary/validators/normal_word.py
@@ -13,8 +13,9 @@ async def normal_words(word: str) -> str:
"""
try:
return word.lower().capitalize()
+
except Exception as e:
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
- from ..loggers.custom_loggers import Logs
+ from ..loggers.logs 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 609e2e2..ceaeb1a 100644
--- a/BotLibrary/validators/url_valid.py
+++ b/BotLibrary/validators/url_valid.py
@@ -1,13 +1,9 @@
# BotLibrary/validators/url_valid.py
# Валидатор ссылок на регулярных выражениях
-import re
-
# Настройка экспорта из этого модуля
__all__ = ("valid_url", "url_to_text")
-
-# Функция определения является ли строка ссылкой
def valid_url(url: str) -> bool:
"""
Проверяет, является ли строка валидной ссылкой (URL).
@@ -15,7 +11,8 @@ def valid_url(url: str) -> bool:
:param url: Строка для проверки.
:return: True, если строка является валидным URL, иначе False.
"""
- url_pattern = re.compile(
+ from re import compile
+ url_pattern = compile(
r'^(https?://)?' # Протокол (http или https, необязателен)
r'([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}' # Домен
r'(:\d+)?' # Порт (необязателен)
@@ -24,7 +21,6 @@ def valid_url(url: str) -> bool:
return bool(url_pattern.match(url))
-# Функция, что дает тексту ссылку на HTML
def url_to_text(text: str, url: str) -> str:
"""
Преобразует текст в HTML ссылку с указанным URL.
@@ -45,7 +41,7 @@ def url_to_text(text: str, url: str) -> str:
except ValueError as e:
# Импортируем Logs внутри функции, чтобы избежать циклического импорта
- from ..loggers.custom_loggers import Logs
+ from ..loggers.logs 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 6f1cfc0..2dab866 100644
--- a/BotLibrary/validators/username.py
+++ b/BotLibrary/validators/username.py
@@ -7,7 +7,6 @@ from aiogram.types import Message
__all__ = ("username", "username_to_text")
-# Функция получения юзера или ID пользователя
def username(message: Message) -> str:
"""
Возвращает юзернейм пользователя из сообщения, или ID, если юзернейм не указан.
@@ -26,7 +25,6 @@ def username(message: Message) -> str:
raise e # Перебрасываем ошибку выше для дальнейшей обработки
-# Функция получение имени пользователя + ссылка на него
def username_to_text(message: Message) -> str:
"""
Преобразует информацию о пользователе в строку с HTML-ссылкой.
diff --git a/Documentation/docs.md b/Documentation/docs.md
index cad3735..ddbd64d 100644
--- a/Documentation/docs.md
+++ b/Documentation/docs.md
@@ -14,15 +14,6 @@
-...
-
-
-
-
-
-
-
-
-
Второй модуль loggers:
logs.py - создает логгеры, три кастомных уровня и 4 обычных. Он может создавать
-NEW_USER
diff --git a/GUI/__init__.py b/GUI/__init__.py
deleted file mode 100644
index 732d5ec..0000000
--- a/GUI/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# GUI/__init__.py
-# Инициализация пакета GUI, для работы с графическим интерфейсом
-
-from .console import *
diff --git a/GUI/console.py b/GUI/console.py
deleted file mode 100644
index f06444b..0000000
--- a/GUI/console.py
+++ /dev/null
@@ -1,167 +0,0 @@
-from tkinter import PhotoImage
-import customtkinter as ctk # модуль для создания стилизованных интерфейсов
-from PIL import Image, ImageTk
-from BotLibrary import * # импорт настроек бота (например, имени, фамилии, и имени пользователя)
-
-# Создание роутера и настройка экспорта
-__all__ = ("App", )
-command_text = "GUI"
-
-
-# Настройка внешнего вида интерфейса
-ctk.set_appearance_mode("System") # Установка режима внешнего вида: "System", "Dark" или "Light"
-ctk.set_default_color_theme("blue") # Установка цветовой темы: "blue", "green", "dark-blue"
-
-
-# Класс приложения, наследующий от customtkinter.CTk
-class App(ctk.CTk):
- def __init__(self):
- super().__init__() # Инициализация базового класса
-
- # Настройка главного окна
- self.title(f"{BotInfo.first_name} {BotInfo.last_name} - @{BotInfo.username}") # Заголовок окна
- self.geometry(f"{700}x{580}") # Размер окна (ширина x высота)
-
- # Настройка сетки (разметка окна на ячейки)
- self.grid_columnconfigure(0, weight=1) # Установка растяжения для 1-го столбца (боковая панель)
- self.grid_columnconfigure(1, weight=9) # Установка растяжения для 2-го столбца (содержимое вкладок)
- self.grid_rowconfigure((0, 1), weight=1) # Установка растяжения для первых трех строк
-
- # Создание боковой панели
- self.sidebar_frame = ctk.CTkFrame(self, width=100, corner_radius=0) # Рамка боковой панели с уменьшенной шириной
- self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") # Расположение в сетке
- self.sidebar_frame.grid_rowconfigure(4, weight=1) # Установка растяжения для 4-й строки
-
- # Логотип на боковой панели
- self.logo_label = ctk.CTkLabel(self.sidebar_frame, text=BotInfo.username,
- font=ctk.CTkFont(size=16, weight="bold")) # Метка с текстом
- self.logo_label.grid(row=0, column=0, padx=10, pady=(20, 10)) # Расположение метки в сетке
-
- # Кнопки на боковой панели
- self.sidebar_button_1 = ctk.CTkButton(self.sidebar_frame, text="Консоль",
- command=self.switch_tab_console,
- font=ctk.CTkFont(size=14))
- self.sidebar_button_1.grid(row=1, column=0, padx=10, pady=10) # Первая кнопка
- self.sidebar_button_2 = ctk.CTkButton(self.sidebar_frame, text="База данных",
- command=self.switch_tab_database,
- font=ctk.CTkFont(size=14))
- self.sidebar_button_2.grid(row=2, column=0, padx=10, pady=10) # Вторая кнопка
- self.sidebar_button_3 = ctk.CTkButton(self.sidebar_frame, text="Иное",
- command=self.switch_tab_other,
- font=ctk.CTkFont(size=14))
- self.sidebar_button_3.grid(row=3, column=0, padx=10, pady=10) # Третья кнопка
-
- # Новые кнопки "Запуск" и "Выключение"
- self.start_button = ctk.CTkButton(self.sidebar_frame, text="Запуск", command=self.start_button_click,
- font=ctk.CTkFont(size=14))
- self.start_button.grid(row=5, column=0, padx=10, pady=10) # Кнопка "Запуск"
-
- self.stop_button = ctk.CTkButton(self.sidebar_frame, text="Выключение",
- command=self.stop_button_click,
- font=ctk.CTkFont(size=14))
- self.stop_button.grid(row=6, column=0, padx=10, pady=10) # Кнопка "Выключение"
-
- # Элементы управления режимами и масштабированием интерфейса
- self.appearance_mode_label = ctk.CTkLabel(self.sidebar_frame, text="Тема UI", anchor="w",
- font=ctk.CTkFont(size=12))
- self.appearance_mode_label.grid(row=7, column=0, padx=10, pady=(10, 0)) # Метка для выбора темы
- self.appearance_mode_optionemenu = ctk.CTkOptionMenu(
- self.sidebar_frame, values=["Светлая", "Темная", "Система"], command=self.change_appearance_mode_event
- ) # Меню выбора темы
- self.appearance_mode_optionemenu.grid(row=8, column=0, padx=10, pady=(10, 10)) # Расположение меню
-
- self.scaling_label = ctk.CTkLabel(self.sidebar_frame, text="Масштабирование",
- anchor="w", font=ctk.CTkFont(size=12)) # Метка для масштабирования
- self.scaling_label.grid(row=9, column=0, padx=10, pady=(10, 0)) # Расположение метки
- self.scaling_optionemenu = ctk.CTkOptionMenu(
- self.sidebar_frame, values=["80%", "90%", "100%", "110%", "120%"], command=self.change_scaling_event
- ) # Меню выбора масштаба
- self.scaling_optionemenu.grid(row=10, column=0, padx=10, pady=(10, 20)) # Расположение меню
-
- # Создание вкладок
- self.tabview = ctk.CTkTabview(self, width=250) # Виджет вкладок
- self.tabview.grid(row=0, column=1, rowspan=3, columnspan=2, padx=(20, 0), pady=(20, 0),
- sticky="nsew") # Растягиваем на все пустое пространство
- self.tabview.add("Консоль") # Первая вкладка
- self.tabview.add("База данных") # Вторая вкладка
- self.tabview.add("Иное") # Третья вкладка
-
- # Вкладка "Консоль" с текстовым полем
- self.textbox_tab_1 = ctk.CTkTextbox(self.tabview.tab("Консоль"))
- self.textbox_tab_1.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
- self.textbox_tab_1.insert("0.0", "Текст в Textbox на вкладке Консоль\n\n")
-
- # Вкладка "База данных" с текстовым полем
- self.textbox_tab_2 = ctk.CTkTextbox(self.tabview.tab("База данных"))
- self.textbox_tab_2.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
- self.textbox_tab_2.insert("0.0", "Текст в Textbox на вкладке База данных\n\n")
-
- # Вкладка "Иное" с текстовым полем
- self.textbox_tab_3 = ctk.CTkTextbox(self.tabview.tab("Иное"))
- self.textbox_tab_3.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
- self.textbox_tab_3.insert("0.0", "Текст в Textbox на вкладке Иное\n\n")
-
- # Растягиваем строки и столбцы вкладок
- self.tabview.grid_rowconfigure(0, weight=1) # Растягиваем строку, где находится текстовое поле
- self.tabview.grid_columnconfigure(0, weight=1) # Растягиваем столбец, где находится текстовое поле
-
- # Убедитесь, что в каждой из вкладок разрешено растяжение:
- self.tabview.tab("Консоль").grid_rowconfigure(0, weight=1)
- self.tabview.tab("База данных").grid_rowconfigure(0, weight=1)
- self.tabview.tab("Иное").grid_rowconfigure(0, weight=1)
-
- self.tabview.tab("Консоль").grid_columnconfigure(0, weight=1)
- self.tabview.tab("База данных").grid_columnconfigure(0, weight=1)
- self.tabview.tab("Иное").grid_columnconfigure(0, weight=1)
-
- # Настройка элементов
- self.appearance_mode_optionemenu.set("Темная") # Режим отображения установлен на "Dark"
- self.scaling_optionemenu.set("100%") # Масштаб интерфейса установлен на 100%
-
- self.update() # Принудительное обновление окна после создания
-
- def change_appearance_mode_event(self, new_appearance_mode: str):
- # Метод для изменения режима отображения интерфейса
- if new_appearance_mode == "Светлая":
- ctk.set_appearance_mode("Light")
- elif new_appearance_mode == "Темная":
- ctk.set_appearance_mode("Dark")
- elif new_appearance_mode == "Система":
- ctk.set_appearance_mode("System")
-
- def change_scaling_event(self, new_scaling: str):
- # Метод для изменения масштаба интерфейса
- new_scaling_float = int(new_scaling.replace("%", "")) / 100
- # Преобразование процента масштаба в дробное число
- ctk.set_widget_scaling(new_scaling_float)
- # Применение нового масштаба ко всем виджетам
-
- def switch_tab_console(self):
- # Переключение на вкладку "Консоль"
- self.tabview.grid(row=0, column=1, rowspan=3, columnspan=2, padx=(20, 0), pady=(20, 0), sticky="nsew")
- self.tabview.set("Консоль")
-
- def switch_tab_database(self):
- # Переключение на вкладку "База данных"
- # Для возвращения вкладок
- self.tabview.grid(row=0, column=1, rowspan=3, columnspan=2, padx=(20, 0), pady=(20, 0), sticky="nsew")
- self.tabview.set("База данных")
-
- def switch_tab_other(self):
- # Переключение на вкладку "Иное"
- self.tabview.grid(row=0, column=1, rowspan=3, columnspan=2, padx=(20, 0), pady=(20, 0), sticky="nsew")
- self.tabview.set("Иное")
-
- def start_button_click(self):
- # Обработчик для кнопки "Запуск"
- print("Запуск")
-
- def stop_button_click(self):
- # Обработчик для кнопки "Выключение"
- print("Выключение")
-
-
-# Начало кода и запуск GUI
-if __name__ == "__main__":
- app = App()
- app.mainloop()
diff --git a/GUI/console_0.py b/GUI/console_0.py
deleted file mode 100644
index ce73298..0000000
--- a/GUI/console_0.py
+++ /dev/null
@@ -1,74 +0,0 @@
-import sys
-import customtkinter as ctk
-import asyncio
-import threading
-
-# Ваши настройки и модули
-from BotLibrary import *
-from BotCode.routers import router as main_router
-from BotCode.routers import set_commands
-
-
-# Класс для перенаправления стандартного вывода в текстовое поле
-class Logger:
- def __init__(self, text_widget):
- self.text_widget = text_widget
-
- def write(self, message):
- self.text_widget.insert("end", message)
- self.text_widget.see("end") # Прокрутка к последнему сообщению
-
- def flush(self):
- pass
-
-
-# Основная функция для запуска бота
-async def main_bot():
- just_fix_windows_console() # Подключение ANSI в Windows CMD
- dp.include_router(main_router) # Подключение главного роутера
-
- await set_all() # Установка настроек бота
- await set_commands() # Установка команд бота
- await bot_get_info() # Получение информации о боте
-
- # Логирование в консоль и текстовое поле
- logger.add(sys.stderr, colorize=True, format=logs_text, level="INFO")
- logger.info(f"Начало запуска бота @{BotInfo.username}...")
-
- bot_info_out() # Включение опроса бота
- await dp.start_polling(bot) # Запуск бота
-
-
-# Класс графического интерфейса
-class BotConsoleWindow(ctk.CTk):
- def __init__(self):
- super().__init__()
-
- # Настройка окна
- self.title("Bot Console")
- self.geometry("800x600")
-
- # Создание текстового поля для логов
- self.log_text = ctk.CTkTextbox(self, wrap="word", width=780, height=500)
- self.log_text.pack(padx=10, pady=10)
-
- # Перенаправление вывода в текстовое поле
- sys.stdout = Logger(self.log_text)
- sys.stderr = Logger(self.log_text)
-
- # Кнопка запуска бота
- self.start_button = ctk.CTkButton(self, text="Запустить бота", command=self.start_bot)
- self.start_button.pack(pady=10)
-
- def start_bot(self):
- self.start_button.configure(state="disabled") # Отключить кнопку
- threading.Thread(target=self.run_bot, daemon=True).start()
-
- def run_bot(self):
- asyncio.run(main_bot())
- self.start_button.configure(state="normal") # Включить кнопку после завершения
-
-
-if __name__ == "__main__":
- app = BotConsoleWindow()
- app.mainloop()
diff --git a/ProjectsFiles/configs/.env b/ProjectsFiles/configs/.env
index 62d5ed9..5cc6816 100644
--- a/ProjectsFiles/configs/.env
+++ b/ProjectsFiles/configs/.env
@@ -2,7 +2,7 @@
# Файл-хранилище всех секретных токенов и ключей
# Токены от ботов телеграмма
-BOT_TOKEN=7162745909:AAF9023WMRMm6uZYldtUcgqB_al4VmZpH1c
+BOT_TOKEN=6393974380:AAFM0F3opRVzCvnhfmNaaNeW5-gJKXwSicU
BOT1_TOKEN=7193685715:AAHFEnFreZGLQcHj8_wdWYJ2FLPrB-A-hzY
BOT2_TOKEN=8076305634:AAGNoo4N-WVP9mbeD76G7SLClSsySw23nGw
diff --git a/ProjectsFiles/configs/config.py b/ProjectsFiles/configs/config.py
index ae9ee80..3a235f5 100644
--- a/ProjectsFiles/configs/config.py
+++ b/ProjectsFiles/configs/config.py
@@ -30,11 +30,11 @@ class BotEdit:
Класс для хранения данных о боте: имя, описание, разрешения и настройки.
"""
# Разрешение на ведение логов
- project_name: str = "Свалка Флуд"
+ project_name: str = "PRIMO"
permission: bool = Permissions.bot_edit
- name: str = "Стартовый бот"
- description: str = "Описание бота"
- short_description: str = "Описание виджета"
+ name: str = "Первозданная Жемчужина"
+ description: str = "Ваш помощник в удивительные миры! Prod. by:『@verdise』"
+ short_description: str = "Тех.поддержка: @verdise"
is_anonymous: bool = False
manage_chat: bool = True
@@ -61,7 +61,8 @@ class BotVar:
encod: str = "utf-8"
language: str = "Python3-Aiogram"
time_format: str = "%Y-%m-%d %H:%M:%S"
- bd_names: str = 'SQLite3/bd.db'
+ bd_names: str = 'ProjectsFiles/database/users.db'
+ bd_path: str = 'ProjectsFiles/database'
prefix: Tuple[str, ...] = ('$', '!', '.', '%', '&', ':', '|', '+', '-', '/', '~', '?')
parse_mode: str = "HTML" # Устанавливаем формат HTML для всех сообщений
diff --git a/SQLite3/bd.db b/ProjectsFiles/database/users.db
similarity index 56%
rename from SQLite3/bd.db
rename to ProjectsFiles/database/users.db
index 58b17b3..3489a3a 100644
Binary files a/SQLite3/bd.db and b/ProjectsFiles/database/users.db differ
diff --git a/SQLite3/__init__.py b/SQLite3/__init__.py
deleted file mode 100644
index 68e6df0..0000000
--- a/SQLite3/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# SQLite3/__init__.py
-# Инициализация пакета SQLite3, для базы данных проекта
-
-# Экспортирование модулей во внешние слои проекта
-from .bd_func import *
diff --git a/SQLite3/bd_func/__init__.py b/SQLite3/bd_func/__init__.py
deleted file mode 100644
index fe1c805..0000000
--- a/SQLite3/bd_func/__init__.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# SQLite3/bd_func/__init__.py
-# Инициализация модуля bd_func, для функция с БД
-
-from aiogram import types
-from BotLibrary.validators import username
-from ProjectsFiles import Permissions
-
-from .bd_add_user import *
-from .bd_get_user import *
-from .bd_update_user import *
-from .bd_update_user_msg import *
-from .bd_user_create import *
-from .status_user import *
-
-
-# Основная обработка SQL
-async def base_sql(message: types.Message) -> None:
- tg_id = message.from_user.id
- usernames = username(message)
- first_name = message.from_user.first_name
- last_name = message.from_user.last_name
-
- if Permissions.sql_user:
- await add_user(tg_id, usernames, first_name, last_name, role="", status="active", user="user")
- await update_user(tg_id=tg_id, first_name=first_name, last_name=last_name)
- await update_user_messages(message=message)
diff --git a/SQLite3/bd_func/bd_add_user.py b/SQLite3/bd_func/bd_add_user.py
deleted file mode 100644
index 939f3a7..0000000
--- a/SQLite3/bd_func/bd_add_user.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# SQLite3/bd_func/bd_add_user.py
-# Добавление пользователя в базу данных bd|user
-
-import sqlite3
-from ProjectsFiles import BotVar
-
-# Настройка экспорта в модули
-__all__ = ("add_user",)
-
-
-# Функция добавления пользователя с последовательным user_id
-async def add_user(tg_id: int, username: str, first_name: str, last_name: str,
- role: str, status: str, user: str, bd_name: str = BotVar.bd_names) -> None:
- with sqlite3.connect(bd_name) as db:
- cursor = db.cursor()
-
- # Проверяем, существует ли пользователь с таким tg_id
- cursor.execute("SELECT user_id FROM users WHERE tg_id = ?", (tg_id,))
- if cursor.fetchone():
- return # Пользователь уже существует, ничего не добавляем
-
- # Находим максимальный user_id
- cursor.execute("SELECT MAX(user_id) FROM users")
- max_id = cursor.fetchone()[0]
- new_user_id = 1 if max_id is None else max_id + 1
-
- # Добавляем нового пользователя
- cursor.execute('''
- INSERT INTO users (user_id, tg_id, username, first_name, last_name, role, status, user)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
- ''', (new_user_id, tg_id, username, first_name, last_name, role, status, user))
-
- # Добавляем запись в user_messages
- cursor.execute('''
- INSERT INTO user_messages (user_id)
- VALUES (?)
- ''', (new_user_id,))
-
- db.commit()
diff --git a/SQLite3/bd_func/bd_get_user.py b/SQLite3/bd_func/bd_get_user.py
deleted file mode 100644
index 16542ac..0000000
--- a/SQLite3/bd_func/bd_get_user.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# SQLite3/bd_func/bd_get_user.py
-# Получение информации о пользователе из базы данных bd|user
-
-import sqlite3
-from ProjectsFiles import BotVar
-
-# Настройка экспорта в модули
-__all__ = ("get_user",)
-
-
-# Функция для получения данных о пользователе
-async def get_user(tg_id: int, bd_name: str = BotVar.bd_names) -> None:
- with sqlite3.connect(bd_name) as db:
- cursor = db.cursor()
- cursor.execute("SELECT * FROM users WHERE tg_id = ?", (tg_id,))
- return cursor.fetchone()
diff --git a/SQLite3/bd_func/bd_update_user.py b/SQLite3/bd_func/bd_update_user.py
deleted file mode 100644
index 86d99b0..0000000
--- a/SQLite3/bd_func/bd_update_user.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# SQLite3/bd_func/bd_update_user.py
-# Обновление данных о пользователях в базу данных bd|user
-
-import sqlite3
-from ProjectsFiles import BotVar
-
-# Настройка экспорта в модули
-__all__ = ("update_user",)
-
-
-# Функция обновления пользователя
-async def update_user(tg_id: int, username: str = None, first_name: str = None, last_name: str = None,
- bd_name: str = BotVar.bd_names, role: str = None, user: str = None) -> None:
- updates = []
- params = []
-
- if username:
- updates.append("username = ?")
- params.append(username)
- if first_name:
- updates.append("first_name = ?")
- params.append(first_name)
- if last_name:
- updates.append("last_name = ?")
- params.append(last_name)
- if role:
- updates.append("role = ?")
- params.append(role)
- if user:
- updates.append("user = ?")
- params.append(user)
-
- if updates:
- query = f"UPDATE users SET {', '.join(updates)} WHERE tg_id = ?"
- params.append(tg_id)
- with sqlite3.connect(bd_name) as db:
- cursor = db.cursor()
- cursor.execute(query, params)
- db.commit()
diff --git a/SQLite3/bd_func/bd_update_user_msg.py b/SQLite3/bd_func/bd_update_user_msg.py
deleted file mode 100644
index b993587..0000000
--- a/SQLite3/bd_func/bd_update_user_msg.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# SQLite3/bd_func/bd_update_user_msg.py
-# Обновление данных о сообщениях пользователя в базу данных bd|message
-
-import sqlite3
-from aiogram import types
-from datetime import timezone, datetime, timedelta
-
-from BotLibrary import type_msg
-from ProjectsFiles import BotVar
-
-# Настройка экспорта в модули
-__all__ = ("update_user_messages",)
-
-
-# Функция обновления статистики сообщений пользователя
-async def update_user_messages(message: types.Message, bd_name: str = BotVar.bd_names) -> None:
- with sqlite3.connect(bd_name) as db:
- cursor = db.cursor()
- user_id = message.from_user.id # Используем user_id напрямую
-
- # Проверяем, существует ли запись в user_messages
- cursor.execute(
- "SELECT last_message_time, messages_per_day, messages_per_week, messages_per_month, total_messages FROM user_messages WHERE user_id = ?",
- (user_id,))
- result = cursor.fetchone()
-
- # Время сообщения в московском времени
- now = message.date.astimezone(timezone(timedelta(hours=3)))
- today = now.date()
- start_of_week = today - timedelta(days=today.weekday()) # Понедельник текущей недели
- current_month = now.month
- current_year = now.year
-
- last_message = message.text or type_msg(message)
- last_message_id = message.message_id
-
- if result:
- last_message_time, messages_per_day, messages_per_week, messages_per_month, total_messages = result
- if last_message_time:
- last_message_time = datetime.fromisoformat(last_message_time).astimezone(timezone(timedelta(hours=3)))
- last_date = last_message_time.date()
- last_week = last_date - timedelta(days=last_date.weekday())
- last_month = last_message_time.month
- last_year = last_message_time.year
-
- # Обнуляем счетчики, если наступил новый день, неделя или месяц
- if last_date != today:
- messages_per_day = 0
- if last_week != start_of_week:
- messages_per_week = 0
- if last_month != current_month or last_year != current_year:
- messages_per_month = 0
- else:
- messages_per_day, messages_per_week, messages_per_month = 0, 0, 0
-
- # Увеличиваем счетчики
- messages_per_day += 1
- messages_per_week += 1
- messages_per_month += 1
- total_messages += 1
- else:
- # Если записи нет, создаем новую
- messages_per_day, messages_per_week, messages_per_month, total_messages = 1, 1, 1, 1
- cursor.execute('INSERT INTO user_messages (user_id, last_message, last_message_id, last_message_time, messages_per_day, messages_per_week, messages_per_month, total_messages) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
- (user_id, last_message, last_message_id, now.isoformat(), messages_per_day, messages_per_week, messages_per_month, total_messages))
- db.commit()
- return
-
- # Обновляем существующую запись
- cursor.execute('''
- UPDATE user_messages
- SET last_message = ?, last_message_id = ?, last_message_time = ?,
- messages_per_day = ?, messages_per_week = ?, messages_per_month = ?,
- total_messages = ?
- WHERE user_id = ?
- ''', (last_message, last_message_id, now.isoformat(), messages_per_day,
- messages_per_week, messages_per_month, total_messages, user_id))
- db.commit()
diff --git a/SQLite3/bd_func/bd_user_create.py b/SQLite3/bd_func/bd_user_create.py
deleted file mode 100644
index 61aafaf..0000000
--- a/SQLite3/bd_func/bd_user_create.py
+++ /dev/null
@@ -1,283 +0,0 @@
-# SQLite3/bd_func/bd_user_create.py
-# Создание базы данных
-
-import sqlite3
-from ProjectsFiles import BotVar
-
-# Настройка экспорта в модули
-__all__ = ("create_user_db",)
-
-
-# Функция создания базы данных
-async def create_user_db(bd_name: str = BotVar.bd_names) -> None:
- with sqlite3.connect(bd_name) as db:
- cursor = db.cursor()
-
- # Таблица пользователей
- cursor.execute('''
- CREATE TABLE IF NOT EXISTS users (
- user_id INTEGER PRIMARY KEY,
- tg_id INTEGER NOT NULL UNIQUE,
- username TEXT,
- first_name TEXT,
- last_name TEXT,
- role TEXT DEFAULT NULL,
- status TEXT DEFAULT 'active',
- user TEXT DEFAULT 'user'
- );''')
-
- # Таблица сообщений пользователей
- cursor.execute('''
- CREATE TABLE IF NOT EXISTS user_messages (
- user_id INTEGER PRIMARY KEY, -- Уникальный ключ
- last_message TEXT,
- last_message_id INTEGER,
- last_message_time TEXT,
- messages_per_day INTEGER DEFAULT 0,
- messages_per_week INTEGER DEFAULT 0,
- messages_per_month INTEGER DEFAULT 0,
- total_messages INTEGER DEFAULT 0,
- FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE
- );''')
-
- # Таблица персонажей
- cursor.execute('''
- CREATE TABLE IF NOT EXISTS characters (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- region TEXT NOT NULL,
- name TEXT NOT NULL,
- status TEXT DEFAULT 'Свободно',
- user_id INTEGER DEFAULT NULL,
- comment TEXT DEFAULT '',
- FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE SET NULL
- );''')
-
- # Таблица персонажей Хонкай
- cursor.execute('''
- CREATE TABLE IF NOT EXISTS characters_hsr (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- region TEXT NOT NULL,
- name TEXT NOT NULL,
- status TEXT DEFAULT 'Свободно',
- user_id INTEGER DEFAULT NULL,
- comment TEXT DEFAULT '',
- FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE SET NULL
- );''')
-
- characters_genshin = [
- # Мондштадт
- ("Мондштадт", "Венти", "Свободно", ""),
- ("Мондштадт", "Кэйа", "Свободно", ""),
- ("Мондштадт", "Альбедо", "Свободно", ""),
- ("Мондштадт", "Дилюк", "Свободно", ""),
- ("Мондштадт", "Мика", "Свободно", ""),
- ("Мондштадт", "Беннет", "Свободно", ""),
- ("Мондштадт", "Рэйзор", "Свободно", ""),
- ("Мондштадт", "Эола", "Свободно", ""),
- ("Мондштадт", "Мона", "Свободно", ""),
- ("Мондштадт", "Джинн", "Свободно", ""),
- ("Мондштадт", "Диона", "Свободно", ""),
- ("Мондштадт", "Лиза", "Свободно", ""),
- ("Мондштадт", "Ноэлль", "Свободно", ""),
- ("Мондштадт", "Сахароза", "Свободно", ""),
- ("Мондштадт", "Розария", "Свободно", ""),
- ("Мондштадт", "Эмбер", "Свободно", ""),
- ("Мондштадт", "Фишль", "Свободно", ""),
- ("Мондштадт", "Барбара", "Свободно", ""),
-
- # Ли Юэ
- ("Ли Юэ", "Чжун Ли", "Свободно", ""),
- ("Ли Юэ", "Сяо", "Свободно", ""),
- ("Ли Юэ", "Син Цю", "Свободно", ""),
- ("Ли Юэ", "Чун Юнь", "Свободно", ""),
- ("Ли Юэ", "Бай Чжу", "Свободно", ""),
- ("Ли Юэ", "Е Лань", "Свободно", ""),
- ("Ли Юэ", "Шень Хэ", "Свободно", ""),
- ("Ли Юэ", "Гань Юй", "Свободно", ""),
- ("Ли Юэ", "Ци Ци", "Свободно", ""),
- ("Ли Юэ", "Кэ Цин", "Свободно", ""),
- ("Ли Юэ", "Янь Фэй", "Свободно", ""),
- ("Ли Юэ", "Нин Гуан", "Свободно", ""),
- ("Ли Юэ", "Бэй Доу", "Свободно", ""),
- ("Ли Юэ", "Яо Яо", "Свободно", ""),
- ("Ли Юэ", "Ка Мин", "Свободно", ""),
- ("Ли Юэ", "Сянь Юнь", "Свободно", ""),
- ("Ли Юэ", "Юнь Цзинь", "Свободно", ""),
- ("Ли Юэ", "Ху Тао", "Свободно", ""),
- ("Ли Юэ", "Лань Янь", "Свободно", ""),
-
- # Инадзума
- ("Инадзума", "Итто", "Свободно", ""),
- ("Инадзума", "Горо", "Свободно", ""),
- ("Инадзума", "Аято", "Свободно", ""),
- ("Инадзума", "Хэйдзо", "Свободно", ""),
- ("Инадзума", "Тома", "Свободно", ""),
- ("Инадзума", "Кадзуха", "Свободно", ""),
- ("Инадзума", "Кирара", "Свободно", ""),
- ("Инадзума", "Кудзё Сара", "Свободно", ""),
- ("Инадзума", "Ёимия", "Свободно", ""),
- ("Инадзума", "Аяка", "Свободно", ""),
- ("Инадзума", "Сангономия Кокоми", "Свободно", ""),
- ("Инадзума", "Яэ Мико", "Свободно", ""),
- ("Инадзума", "Райдэн Эи", "Свободно", ""),
- ("Инадзума", "Саю", "Свободно", ""),
- ("Инадзума", "Куки Синобу", "Свободно", ""),
- ("Инадзума", "Мидзуки", "Свободно", ""),
-
- # Сумеру
- ("Сумеру", "Аль-Хайтам", "Свободно", ""),
- ("Сумеру", "Кавех", "Свободно", ""),
- ("Сумеру", "Сайно", "Свободно", ""),
- ("Сумеру", "Тигнари", "Свободно", ""),
- ("Сумеру", "Сетос", "Свободно", ""),
- ("Сумеру", "Нилу", "Свободно", ""),
- ("Сумеру", "Нахида", "Свободно", ""),
- ("Сумеру", "Лайла", "Свободно", ""),
- ("Сумеру", "Кандакия", "Свободно", ""),
- ("Сумеру", "Дори", "Свободно", ""),
- ("Сумеру", "Дэхья", "Свободно", ""),
- ("Сумеру", "Коллеи", "Свободно", ""),
- ("Сумеру", "Фарузан", "Свободно", ""),
-
- # Фонтейн
- ("Фонтейн", "Лини", "Свободно", ""),
- ("Фонтейн", "Ризли", "Свободно", ""),
- ("Фонтейн", "Невиллет", "Свободно", ""),
- ("Фонтейн", "Фремине", "Свободно", ""),
- ("Фонтейн", "Линетт", "Свободно", ""),
- ("Фонтейн", "Эмилия", "Свободно", ""),
- ("Фонтейн", "Клоринда", "Свободно", ""),
- ("Фонтейн", "Навия", "Свободно", ""),
- ("Фонтейн", "Шарлотта", "Свободно", ""),
- ("Фонтейн", "Фурина", "Свободно", ""),
- ("Фонтейн", "Тиори", "Свободно", ""),
- ("Фонтейн", "Сиджвин", "Свободно", ""),
-
- # Натлан
- ("Натлан", "Кинич", "Свободно", ""),
- ("Натлан", "Оророн", "Свободно", ""),
- ("Натлан", "Муалани", "Свободно", ""),
- ("Натлан", "Ситлали", "Свободно", ""),
- ("Натлан", "Шилонен", "Свободно", ""),
- ("Натлан", "Иансан", "Свободно", ""),
- ("Натлан", "Мавуика", "Свободно", ""),
- ("Натлан", "Часка", "Свободно", ""),
-
- # Фатуи
- ("Фатуи", "Тарталья", "Свободно", ""),
- ("Фатуи", "Панталоне", "Свободно", ""),
- ("Фатуи", "Дотторе", "Свободно", ""),
- ("Фатуи", "Капитано", "Свободно", ""),
- ("Фатуи", "Пьеро", "Свободно", ""),
- ("Фатуи", "Пульничелла", "Свободно", ""),
- ("Фатуи", "Синьора", "Свободно", ""),
- ("Фатуи", "Арлекино", "Свободно", ""),
- ("Фатуи", "Коломбина", "Свободно", ""),
- ("Фатуи", "Царица", "Свободно", ""),
- ("Фатуи", "Странник", "Свободно", ""),
-
- # Иные персонажи
- ("Иные персонажи", "Итэр", "Свободно", ""),
- ("Иные персонажи", "Люмин", "Свободно", ""),
- ("Иные персонажи", "Элой", "Свободно", ""),
- ("Иные персонажи", "Паймон", "Свободно", ""),
- ("Иные персонажи", "Дайнслейф", "Свободно", ""),
- ]
-
- characters_hsr = [
- # Ярило-6
- ("Ярило-6", "Броня", "Свободно", ""),
- ("Ярило-6", "Гепард", "Свободно", ""),
- ("Ярило-6", "Зеле", "Свободно", ""),
- ("Ярило-6", "Клара", "Свободно", ""),
- ("Ярило-6", "Лука", "Свободно", ""),
- ("Ярило-6", "Наташа", "Свободно", ""),
- ("Ярило-6", "Пела", "Свободно", ""),
- ("Ярило-6", "Рысь", "Свободно", ""),
- ("Ярило-6", "Сампо", "Свободно", ""),
- ("Ярило-6", "Сервал", "Свободно", ""),
- ("Ярило-6", "Хук", "Свободно", ""),
-
- # Станция «Герта»
- ("Станция «Герта»", "Арлан", "Свободно", ""),
- ("Станция «Герта»", "Аста", "Свободно", ""),
- ("Станция «Герта»", "Великая Герта", "Свободно", ""),
- ("Станция «Герта»", "Кукла «Герта»", "Свободно", ""),
- ("Станция «Герта»", "Жуань Мэй", "Свободно", ""),
-
- # Пенакония
- ("Пенакония", "Авантюрин", "Свободно", ""),
- ("Пенакония", "Ахерон", "Свободно", ""),
- ("Пенакония", "Галлахер", "Свободно", ""),
- ("Пенакония", "Зарянка", "Свободно", ""),
- ("Пенакония", "Миша", "Свободно", ""),
- ("Пенакония", "Мистер Река", "Свободно", ""),
- ("Пенакония", "Раппа", "Свободно", ""),
- ("Пенакония", "Чёрный Лебедь", "Свободно", ""),
- ("Пенакония", "Яшма", "Свободно", ""),
- ("Пенакония", "Воскресенье", "Свободно", ""),
-
- # Звёздный Экспресс
- ("Звёздный Экспресс", "Вельт", "Свободно", ""),
- ("Звёздный Экспресс", "Келус", "Свободно", ""),
- ("Звёздный Экспресс", "Стелла", "Свободно", ""),
- ("Звёздный Экспресс", "Дань Хэн", "Свободно", ""),
- ("Звёздный Экспресс", "Март 7", "Свободно", ""),
- ("Звёздный Экспресс", "Химеко", "Свободно", ""),
- ("Звёздный Экспресс", "Пом Пом", "Свободно", ""),
-
- # Галактика
- ("Галактика", "Аргенти", "Свободно", ""),
- ("Галактика", "Блэйд", "Свободно", ""),
- ("Галактика", "Бутхилл", "Свободно", ""),
- ("Галактика", "Доктор Рацио", "Свободно", ""),
- ("Галактика", "Кафка", "Свободно", ""),
- ("Галактика", "Светлячок", "Свободно", ""),
- ("Галактика", "Искорка", "Свободно", ""),
- ("Галактика", "Серебряный Волк", "Свободно", ""),
- ("Галактика", "Топаз", "Свободно", ""),
-
- # Амфореус
- ("Амфореус", "Аглая", "Свободно", ""),
- ("Амфореус", "Мидей", "Свободно", ""),
- ("Амфореус", "Трибби", "Свободно", ""),
-
- # Альянс Сяньчжоу
- ("Альянс Сяньчжоу", "Байлу", "Свободно", ""),
- ("Альянс Сяньчжоу", "Гуйнайфей", "Свободно", ""),
- ("Альянс Сяньчжоу", "Линша", "Свободно", ""),
- ("Альянс Сяньчжоу", "Лоча", "Свободно", ""),
- ("Альянс Сяньчжоу", "Моцзэ", "Свободно", ""),
- ("Альянс Сяньчжоу", "Пожиратель Луны", "Свободно", ""),
- ("Альянс Сяньчжоу", "Сушан", "Свободно", ""),
- ("Альянс Сяньчжоу", "Сюзи", "Свободно", ""),
- ("Альянс Сяньчжоу", "Фуга", "Свободно", ""),
- ("Альянс Сяньчжоу", "Фэйсяо", "Свободно", ""),
- ("Альянс Сяньчжоу", "Ханья", "Свободно", ""),
- ("Альянс Сяньчжоу", "Хохо", "Свободно", ""),
- ("Альянс Сяньчжоу", "Цзин Юань", "Свободно", ""),
- ("Альянс Сяньчжоу", "Цзиннлю", "Свободно", ""),
- ("Альянс Сяньчжоу", "Цзяоцю", "Свободно", ""),
- ("Альянс Сяньчжоу", "Цинцюэ", "Свободно", ""),
- ("Альянс Сяньчжоу", "Юйкун", "Свободно", ""),
- ("Альянс Сяньчжоу", "Юньли", "Свободно", ""),
- ("Альянс Сяньчжоу", "Яньцин", "Свободно", ""),
- ]
-
- # Проверяем, пуста ли таблица characters
- cursor.execute("SELECT COUNT(*) FROM characters;")
- if cursor.fetchone()[0] == 0:
- cursor.executemany('''
- INSERT INTO characters (region, name, status, comment)
- VALUES (?, ?, ?, ?);
- ''', characters_genshin)
-
- # Проверяем, пуста ли таблица characters_hsr
- cursor.execute("SELECT COUNT(*) FROM characters_hsr;")
- if cursor.fetchone()[0] == 0:
- cursor.executemany('''
- INSERT INTO characters_hsr (region, name, status, comment)
- VALUES (?, ?, ?, ?);
- ''', characters_hsr)
-
- db.commit()
diff --git a/SQLite3/bd_func/status_user.py b/SQLite3/bd_func/status_user.py
deleted file mode 100644
index dab1f4b..0000000
--- a/SQLite3/bd_func/status_user.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# SQLite3/bd_func/status_user.py
-# Проверка статусов пользователя с БД
-
-import sqlite3
-from aiogram import types
-from ProjectsFiles import BotVar
-
-# Функция проверки статуса пользователя
-async def status_user(message: types.Message, bd_path: str = BotVar.bd_names) -> str:
- # Подключение к базе данных
- bd = sqlite3.connect(bd_path)
- tg_id = message.from_user.id
- cursor = bd.cursor()
-
- # Запрос к базе данных для получения значения из столбца 'user' для конкретного tg_id
- cursor.execute("SELECT user FROM users WHERE tg_id = ?", (tg_id,))
-
- # Получаем результат
- row = cursor.fetchone()
-
- # Словарь для сопоставления статусов
- status_map = {
- "ban": "Забаннен",
- "user": "Пользователь",
- "moderator": "Модератор",
- "admin": "Администратор",
- "so-owner": "Совладелец",
- "owner": "Владелец",
- }
-
- if row:
- user_type = row[0] # предполагаем, что в столбце 'user' находится только одно значение
- status: str = status_map.get(user_type, "Ошибка!") # Получаем статус или "Ошибка!"
- else:
- status: str = "Пользователь не найден"
-
- # Закрываем соединение с базой данных
- bd.close()
-
- # Выводим статус
- return status
diff --git a/SQLite3/bd_func/username_to_id.py b/SQLite3/bd_func/username_to_id.py
deleted file mode 100644
index cfbe136..0000000
--- a/SQLite3/bd_func/username_to_id.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# SQLite3/bd_func/username_to_id.py
-#
-
diff --git a/SQLite3/list_ids.json b/SQLite3/list_ids.json
deleted file mode 100644
index 67a513a..0000000
--- a/SQLite3/list_ids.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "ban_list_ids": {
- "6666666666666": "Забанненый"
- },
- "important_adm_ids": {
- "6751720805": "Лейн",
- "7051557370": "Рикси",
- "1570652377": "Риша",
- "1398573474": "Финаки",
- "1851081467": "Финик",
- "929782381": "Хиде",
- "6714237814": "Слешик",
- "1686743480": "Полина",
- "1184519857": "Катаз"
- },
- "important_groups_ids": {
- "1087968824": "GroupAnonymousBot",
- "-1002442589033": "Любовники Сергея",
- "-1002124483077": "Труба_Сквад",
- "-1002123850090": "Тест_Чат",
- "-1001552311087": "Все_Будет_Хорошо"
- },
- "important_users_list_ids": {
- "7145369362": "Артур",
- "1219440132": "Данил",
- "1443833264": "Виктор",
- "5424384921": "Олег",
- "556943853": "Ваня",
- "1295708467": "Степан"
- },
- "important_channel_ids": {
- "10000000000000": "Канал1",
- "20000000000000": "Канал2"
- }
-}
diff --git a/Test/commands/ban_cmd.py b/Test/commands/ban_cmd.py
deleted file mode 100644
index c022f72..0000000
--- a/Test/commands/ban_cmd.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# BotCode/routers/commands/admin_cmd/ban_cmd.py
-# Работа с админ-командой /ban, для блокировки пользователей (в разработке)
-# Проверка на наличие блокировки пользователя в боте
-
-
-from aiogram import Router, types
-from aiogram.filters import Command
-from BotLibrary import *
-
-# Создание роутера и настройка экспорта
-__all__ = ("router", "banned_user", "ban_user_by_username",)
-router = Router(name="ban_router")
-command_text = "BAN"
-
-
-# Функция проверки блокировки пользователя в боте
-@router.message(lambda message: message.from_user.id in ListId.ban_list_id)
-async def banned_user(message: types_msg.Message):
- try:
- # Вывод сообщения пользователю
- chat_id = await find_chat_id(message)
- text = (f"{TextDecorator.RED}Получено сообщение от забанненго пользователя"
- f" из ({chat_id}) : {message.text}{TextDecorator.RESET_DECORATOR}")
- await message.answer(f"Вы были забаннены в боте @{BotInfo.username}!")
-
- # Активация логгера
- await cmd_logginger(message, command_text, text)
-
- return text
-
- # Проверка на ошибку и ее логирование
- except Exception as e:
- text_error = await error_cmd_logginger(message, command_text, e)
- return text_error
-
-
-# Обработчик команды /ban
-@router.message(Command("ban", "ифт", "бан", ",fy", prefix=BotEdit.prefixs, ignore_case=True))
-async def ban_user_by_username(message: types_msg.Message):
- try:
- text = f"использовал(а) команду /{command_text.lower()}"
-
- # Получаем аргументы команды
- args = message.get_args() # Вернет все, что идет после /ban
-
- # Проверка на наличие аргумента
- if not args:
- text = f"Пожалуйста, укажите ID или имя пользователя для бана. Пример: /ban 123456"
- await message.reply(text)
- return text
-
- # Вывод сообщения пользователю
- await message.reply(text=f"Вы попытались забанить, обидно да?")
-
- # Активация логгера
- await cmd_logginger(message, command_text, text)
-
- return text
-
- # Проверка на ошибку и ее логирование
- except Exception as e:
- text_error = await error_cmd_logginger(message, command_text, e)
- return text_error
diff --git a/Test/commands/find_username.py b/Test/commands/find_username.py
deleted file mode 100644
index 7733ca5..0000000
--- a/Test/commands/find_username.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# BotLibrary/analitics/find_username.py
-# Нахождение юзернейма пользователя по id (в разработке)
-
-from loguru import logger
-from BotLibrary.library.bots import bot
-
-# Настройка экспорта
-__all__ = ("get_user_id_by_username",)
-type_messages = "ID_USERNAME"
-
-
-# Получение ID пользователя по юзернейму (в разработке)
-async def get_user_id_by_username(chat_id, username):
- try:
- user = await bot.get_chat_member_by_username(chat_id, username)
- if user:
- return user.user.id
- else:
- return None
-
- # Проверка на ошибку и ее логирование (в разработке)
- except Exception as e:
- text_error = f"Ошибка при получении ID пользователя: {e}"
- logger.bind(custom_variable="IDS", user_var=type_messages).error(text_error)
- return text_error
diff --git a/Test/old_files/__init__.py b/Test/old_files/__init__.py
deleted file mode 100644
index 492dcdc..0000000
--- a/Test/old_files/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# BotCode/routers/old_files/__init__.py
-# Инициализация старого пакета old_files, для хранения старых функций
-
-from aiogram import Router
-from .media_func import router as media_old_router
-from .regular_handlers import router as regular_router
-
-
-# Объявление роутера и настройка экспорта
-__all__ = ("router",)
-router = Router(name="old_files_router")
-
-
-# Список подключаемых роутеров сверху-вниз
-router.include_routers(
- regular_router,
- media_old_router,
-)
-
-
-# Список подключаемых роутеров сверху-вниз
-router.include_routers()
diff --git a/Test/old_files/media_func.py b/Test/old_files/media_func.py
deleted file mode 100644
index ac76469..0000000
--- a/Test/old_files/media_func.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# BotCode/routers/old_files/media_func.py
-# Некоторые функции для работы с медиа-сообщениями
-
-from re import Match
-from aiogram import Router, F, types
-from magic_filter import RegexpMode
-from BotLibrary import *
-
-# Настройка экспорта модулей и роутера
-__all__ = ("router",)
-router = Router(name="media_func")
-
-
-# @router.message(F.photo, ~F.caption)
-async def handle_photo_wo_caption(message: types_msg.Message):
- caption = f"Простите, я не могу это увидеть. Вы можете описать что это?"
- await message.reply_photo(
- photo=message.photo[-1].file_id,
- caption=caption,
- )
- return caption
-
-
-# @router.message(F.photo, F.caption.contains("please"))
-async def handle_photo_with_please_caption(message: types_msg.Message):
- text = f"Простите, я не могу это увидеть."
- await message.reply(text)
- return text
-
-
-# @router.message(any_media_filter, ~F.caption)
-async def handle_any_media_wo_caption(message: types_msg.Message):
- if message.document:
- await message.reply_document(
- document=message.document.file_id,
- )
- return f"Перессылка документа"
-
- elif message.video:
- await message.reply_video(
- video=message.video.file_id,
- )
- return f"Перессылка видео"
-
- else:
- text = f"Я не могу это увидеть."
- await message.reply(text)
- return text
-
-
-# @router.message(any_media_filter, F.caption)
-async def handle_any_media_w_caption(message: types_msg.Message):
- text = f"Что-то на медиа. Твой текст: {message.caption!r}"
- await message.reply(text)
- return text
diff --git a/main.py b/main.py
index 2219858..99e7f7a 100644
--- a/main.py
+++ b/main.py
@@ -1,21 +1,39 @@
# main.py
# Основной код проекта, который и соединяет в себе все его возможности
-import asyncio
from BotLibrary import *
-from BotCode import router as main_router
+from ProjectsFiles import Permissions
+from BotCode import router as main_routers
# Запуск основного кода
-async def main():
- # Функция установки
- await setup()
+async def main() -> None:
+ # Запуск логеров
+ Logs.setup()
+
+ # Получение информации о боте
+ await BotInfo.info()
+
+ # Вывод сообщение о запуске
+ Logs.start(text=f"Начало запуска бота @{BotInfo.username}...")
+
+ # Создание пустых директорий
+ await Directory.setup()
+
+ # Нужно ли удалить веб-хук
+ if Permissions.delete_webhook:
+ await bot.delete_webhook()
+
+ # Установка необходимых прав
+ await BotRights.all(bot)
+ Logs.console()
# Подключение главного маршрутизатора
- dp.include_router(main_router)
+ dp.include_router(main_routers)
# Включение опроса бота
await dp.start_polling(bot)
# Вечная загрузка бота
if __name__ == "__main__":
- asyncio.run(main())
+ from asyncio import run
+ run(main())
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..e984e1f
Binary files /dev/null and b/requirements.txt differ