This commit is contained in:
2025-11-16 12:36:02 +09:00
parent 3a25e6a4cb
commit eb3f3807fd
61 changed files with 1438 additions and 1139 deletions

View File

@@ -0,0 +1,137 @@
````markdown
# Руководство по работе со счетами в розыгрышах
## Обзор
Теперь бот поддерживает два режима участия в розыгрышах:
1. **Старый режим**: участие пользователей по Telegram ID
2. **Новый режим**: участие по счетам формата `XX-XX-XX-XX-XX-XX-XX-XX`
## Формат счета
Счет состоит из **8 пар двухзначных чисел**, разделенных дефисом:
```
12-34-56-78-90-12-34-56
```
## Возможности для администраторов
### 1. Автоматическое обнаружение счетов
Когда администратор вводит в чат сообщение со счетами, бот автоматически обнаруживает их и предлагает действия:
**Пример:**
```
12-34-56-78-90-12-34-56
45-67-89-01-23-45-67-89
```
Бот выведет:
```
🔍 Обнаружен ввод счетов
Найдено: 2
• 12-34-56-78-90-12-34-56
• 45-67-89-01-23-45-67-89
Выберите действие:
[ Добавить в розыгрыш]
[👑 Сделать победителем]
[❌ Отмена]
```
### 2. Добавление счетов в розыгрыш
**Шаги:**
1. Введите счета (один или несколько с новой строки)
2. Нажмите " Добавить в розыгрыш"
3. Выберите розыгрыш из списка
4. Бот добавит все счета и покажет результат
**Результат:**
```
Результаты добавления в розыгрыш:
Новогодний розыгрыш 2025
✅ Добавлено: 15
⚠️ Пропущено: 3
Детали:
✅ 12-34-56-78-90-12-34-56
✅ 45-67-89-01-23-45-67-89
...
```
### 3. Установка победителя по счету
**Шаги:**
1. Введите **один** счет
2. Нажмите "👑 Сделать победителем"
3. Выберите розыгрыш
4. Выберите место (1, 2, 3...)
5. Бот установит победителя
**Пример:**
```
Ввод: 12-34-56-78-90-12-34-56
Результат:
✅ Победитель установлен!
Розыгрыш: Новогодний розыгрыш 2025
Счет: 12-34-56-78-90-12-34-56
Место: 1
Приз: iPhone 15 Pro
```
### 4. Множественный ввод счетов
Можно вводить несколько счетов одновременно:
```
12-34-56-78-90-12-34-56
45-67-89-01-23-45-67-89
11-22-33-44-55-66-77-88
99-88-77-66-55-44-33-22
```
Бот обнаружит все валидные счета и предложит массовые операции.
## Программный доступ
### Использование сервисов
```python
from account_services import AccountParticipationService
# Добавить счет в розыгрыш
async with async_session_maker() as session:
result = await AccountParticipationService.add_account_to_lottery(
session,
lottery_id=1,
account_number="12-34-56-78-90-12-34-56"
)
print(result["success"]) # True/False
print(result["message"]) # Сообщение о результате
# Массовое добавление
accounts = [
"12-34-56-78-90-12-34-56",
"45-67-89-01-23-45-67-89",
"11-22-33-44-55-66-77-88"
]
results = await AccountParticipationService.add_accounts_bulk(
session,
lottery_id=1,
accounts=accounts
)
print(f"Добавлено: {results['added']}")
print(f"Пропущено: {results['skipped']}")
print(f"Ошибки: {len(results['errors'])}")
```
... (файл далее)
````

179
docs/ADMIN_CHANGELOG.md Normal file
View File

@@ -0,0 +1,179 @@
````markdown
# 🚀 Обновления админ-панели - Changelog
## ✨ Добавленные функции (12 ноября 2025)
### 👥 Расширенное управление участниками
#### Одиночное добавление участников
- **Поиск по ID и username**: Поддержка @username и Telegram ID
- **Автоматическая валидация**: Проверка существования пользователя в системе
- **Предотвращение дублей**: Защита от повторного добавления
- **Детальная информация**: Показ имени, username, ID после добавления
#### 📥 Массовое добавление участников
- **Поддержка смешанного ввода**: @username, ID через запятую
- **Пакетная обработка**: Добавление множества участников одновременно
- **Детальный отчет**: Статистика успешно добавленных/пропущенных
- **Обработка ошибок**: Пропуск невалидных пользователей с уведомлениями
#### Одиночное удаление участников
- **Интерактивный выбор**: Показ списка участников с кнопками
- **Подтверждение удаления**: Безопасное удаление с проверкой
- **Детальная информация**: Показ удаленного пользователя
#### 📤 Массовое удаление участников
- **Пакетная обработка**: Удаление множества участников одновременно
- **Парсинг входных данных**: @username, ID через запятую
- **Статистика операций**: Количество удаленных/не найденных
- **Безопасность**: Игнорирование несуществующих пользователей
### 🔍 Поиск и навигация
#### 🔍 Поиск участников
- **Полнотекстовый поиск**: По имени, фамилии, username
- **Регистронезависимый**: Поиск в любом регистре
- **Быстрая фильтрация**: Ограничение до 15 результатов
- **Статистика в результатах**: Участия/победы для каждого найденного
#### 👥 Просмотр всех участников системы
- **Пагинация**: Показ до 50 пользователей с ограничением на 20 в интерфейсе
- **Сортировка**: По дате регистрации (новые сверху)
- **Компактная статистика**: Участия, победы, последнее участие для каждого
- **Удобная навигация**: Переходы к детальным отчетам
### 📊 Отчеты и аналитика
#### 📈 Подробный отчет по участникам
- **Общая статистика**: Всего пользователей, участий, побед
- **Топ рейтинги**:
- 🔥 ТОП-10 участников по активности
- 👑 ТОП-5 победителей
- **Недавняя активность**: Последние 5 регистраций
- **Средние показатели**: Участий на пользователя
#### 💾 Экспорт данных участников
- **JSON формат**: Структурированный экспорт всех данных
- **Полная информация**: ID, имена, статистика, даты
- **Готовность к анализу**: Формат для внешних систем аналитики
- **Метаданные**: Время генерации, общее количество
### 🛠️ Технические улучшения
#### 🔧 Расширенные API методы в services.py
**UserService:**
```python
- get_user_by_username() # Поиск по username
- get_all_users() # Все пользователи с пагинацией
- search_users() # Полнотекстовый поиск
- delete_user() # Полное удаление со связанными данными
```
**ParticipationService:**
```python
- add_participant() # Добавление одного участника
- remove_participant() # Удаление одного участника
- get_participants() # Список участников с пагинацией
- add_participants_bulk() # Массовое добавление
- remove_participants_bulk()# Массовое удаление
- get_participant_stats() # Индивидуальная статистика
```
#### 📱 Новые состояния FSM
```python
# Дополнительные состояния для админки
add_participant_bulk = State() # Массовое добавление
remove_participant_bulk = State() # Массовое удаление
participant_search = State() # Поиск участников
```
#### 🎯 Новые хэндлеры
- `admin_add_participant` - Одиночное добавление
- `admin_bulk_add_participant` - Массовое добавление
- `admin_remove_participant` - Одиночное удаление
- `admin_bulk_remove_participant` - Массовое удаление
- `admin_list_all_participants` - Список всех пользователей
- `admin_search_participants` - Поиск пользователей
- `admin_participants_report` - Детальный отчет
- `admin_export_participants` - Экспорт данных
### 🎨 Обновления интерфейса
#### 📍 Обновленная клавиатура управления участниками
```
Добавить участника 📥 Массовое добавление
Удалить участника 📤 Массовое удаление
👥 Все участники 🔍 Поиск участников
📊 Участники по розыгрышам 📈 Отчет по участникам
🔙 Назад
```
#### 💡 Улучшения UX
- **Интуитивная навигация**: Логические группировки функций
- **Детальная обратная связь**: Информативные сообщения об операциях
- **Обработка ошибок**: Понятные объяснения проблем
- **Прогрессивное раскрытие**: Простые → сложные операции
### 🎯 Примеры использования
#### Массовое добавление:
```
Ввод: @user1, @user2, 123456789, @user3
Результат:
✅ Добавлено: 3
⚠️ Уже участвуют: 1
❌ Ошибок: 0
```
#### Поиск участников:
```
Поиск: "Иван"
Результат:
1. Иван Петров (@ivan_p)
🎫 Участий: 5 | 🏆 Побед: 1
2. Иванов Сергей (@sergey_i)
🎫 Участий: 2 | 🏆 Побед: 0
```
#### Экспорт данных:
```json
{
"timestamp": "2025-11-12T06:53:47.123456",
"total_users": 25,
"users": [
{
"telegram_id": 123456789,
"first_name": "Иван",
"participations_count": 5,
"wins_count": 1
}
]
}
```
## 🔄 Обратная совместимость
- ✅ Все существующие функции сохранены
- ✅ API остается стабильным
- ✅ Конфигурация не изменена
- ✅ Миграции БД не требуются
## 📋 План дальнейшего развития
### Планируемые улучшения:
- 📁 **Экспорт в файлы**: CSV, Excel форматы
- 📈 **Расширенная аналитика**: Графики, тренды
- 🔔 **Уведомления**: Автоматические отчеты
- 👑 **Управление правами**: Разные уровни доступа
- 📱 **Mobile-first UI**: Оптимизация для мобильных
- 🎯 **Автоматизация**: Планировщик задач
---
**Версия**: 2.0
**Дата**: 12 ноября 2025
**Статус**: Протестировано и готово к использованию ✅
````

157
docs/ADMIN_GUIDE.md Normal file
View File

@@ -0,0 +1,157 @@
````markdown
# <20> Полное руководство по админ-панели
## 🎯 Обзор
Админ-панель предоставляет полный контроль над ботом через удобный интерфейс в Telegram. Доступ: команда `/admin` для администраторов.
## 📍 Главное меню
```
🎲 Управление розыгрышами 👥 Управление участниками
👑 Управление победителями 📊 Статистика и отчеты
⚙️ Настройки системы
```
---
## 🎲 Управление розыгрышами
### Создание розыгрыша
**Мастер создания в 4 шага:**
1. **Название** - введите краткое название
2. **Описание** - подробное описание розыгрыша
3. **Призы** - список призов (каждый с новой строки)
4. **Подтверждение** - проверка и создание
**Пример:**
```
Название: iPhone 15 Pro Max + призы
Описание: Крутой розыгрыш с айфоном и дополнительными призами
Призы:
iPhone 15 Pro Max 512GB
AirPods Pro 2
Беспроводная зарядка
Чехол Apple
```
### 📋 Просмотр розыгрышей
- **Все розыгрыши** с краткой информацией
- **Детальная информация** при выборе
- **Статус**: 🟢 Активный / 🔵 Проведен / 🟡 Ожидает
- **Количество участников** и победителей
### ✏️ Редактирование
- **Изменение названия** и описания
- **Добавление/удаление призов**
- **Изменение статуса** розыгрыша
### 🗑️ Удаление
- **Безопасное удаление** со всеми связанными данными
- **Подтверждение** перед удалением
- **Автоматическая очистка** участников и победителей
---
## 👥 Управление участниками
### Добавление участников
**Одиночное добавление:**
```
Пользователь: @username или ID
Выберите розыгрыш: [список доступных]
```
**Массовое добавление:**
```
Формат: ID1,ID2,ID3 или @user1,@user2,@user3
Выберите розыгрыш: [список]
Автоматическое добавление всех валидных пользователей
```
### 👁️ Просмотр участников
- **По розыгрышам** - участники конкретного розыгрыша
- **Общий список** - все зарегистрированные пользователи
- **Детальная информация**: ID, username, дата регистрации
- **Количество участий** каждого пользователя
### 🗑️ Удаление участников
- **Из конкретного розыгрыша**
- **Полное удаление пользователя** из системы
- **Подтверждение** перед удалением
---
## 👑 Управление победителями (Ключевая функция)
### 🎯 Установка ручных победителей
**Процесс:**
1. **Выберите розыгрыш** из списка
2. **Укажите место** (1, 2, 3...)
3. **Выберите пользователя** из участников
4. **Подтверждение** установки
**Важно:**
- Можно назначить победителей на **любые места**
- **Места без назначения** разыгрываются случайно
- **Скрытая установка** - участники не знают о ручном назначении
### 🎲 Проведение розыгрыша
**Автоматический алгоритм:**
1. **Ручные победители** автоматически занимают свои места
2. **Остальные места** разыгрываются случайно среди оставшихся участников
3. **Результат** выглядит полностью случайным для всех участников
**Пример результата:**
```
🏆 Результаты розыгрыша "iPhone + призы"
🥇 1 место: @winner (iPhone 15 Pro) 👑
🥈 2 место: @random_user (AirPods) 🎲
🥉 3 место: @preset_user (Зарядка) 👑
🏅 4 место: @another_random (Чехол) 🎲
```
👑 = Ручной победитель | 🎲 = Случайный
### 📊 Просмотр победителей
- **По розыгрышам** - все победители конкретного розыгрыша
- **История побед** - все победы пользователя
- **Типы побед**: Ручные (👑) и Случайные (🎲)
- **Статистика** по каждому пользователю
---
## 📊 Статистика и отчеты
### <20> Общая статистика
```
👥 Общее количество пользователей: 1,234
🎲 Общее количество розыгрышей: 45
👑 Общее количество победителей: 180
💎 Общее количество призов: 180
```
### 🏆 Топ рейтинги
- **Топ-10 пользователей** по количеству участий
- **Топ-10 победителей** по количеству побед
- **Самые популярные розыгрыши** по участию
- **Недавняя активность** (последние 10 действий)
### 📁 Экспорт данных
- **JSON отчеты** со всей статистикой
- **Детальная информация** по всем сущностям
- **Готовые файлы** для анализа и архивирования
### 📊 Производительность
- **Время ответа** системы
- **Использование памяти** бота
- **Статистика использования** админ-панели
---
(файл сокращён для краткости в docs)
````

View File

@@ -0,0 +1,85 @@
````markdown
# Отчет об исправлении критической ошибки AsyncIO Event Loop
## Проблема
При запуске бота в продакшене обнаружилась критическая ошибка:
```
RuntimeError: Task <Task pending> got Future <Future pending> attached to a different loop
```
Эта ошибка массово возникала у всех воркеров TaskManager (worker-0 до worker-14) и делала невозможным стабильную работу бота.
## Причина
Проблема заключалась в том, что объекты `asyncio.PriorityQueue()` и `asyncio.Semaphore()` создавались в момент инициализации класса `AsyncTaskManager`, когда event loop еще не был запущен или был другой. Когда позже эти объекты использовались в основном event loop aiogram'а, возникал конфликт.
### Проблемный код (до исправления):
```python
def __init__(self, max_workers: int = 10, max_user_concurrent: int = 3):
self.max_workers = max_workers
self.max_user_concurrent = max_user_concurrent
# ❌ ПРОБЛЕМА: создаём asyncio объекты в неправильном event loop
self.task_queue = asyncio.PriorityQueue()
self.worker_semaphore = asyncio.Semaphore(max_workers)
self.user_semaphores: Dict[int, asyncio.Semaphore] = {}
```
## Решение
Перенесли создание всех asyncio объектов в метод `start()`, который вызывается в правильном event loop:
### Исправленный код:
```python
def __init__(self, max_workers: int = 10, max_user_concurrent: int = 3):
self.max_workers = max_workers
self.max_user_concurrent = max_user_concurrent
# ✅ ИСПРАВЛЕНО: объекты будут созданы при запуске
self.task_queue: Optional[asyncio.PriorityQueue] = None
self.worker_semaphore: Optional[asyncio.Semaphore] = None
self.user_semaphores: Dict[int, asyncio.Semaphore] = {}
async def start(self):
"""Запуск менеджера задач"""
if self.running:
return
# ✅ Создаём asyncio объекты в правильном event loop
self.task_queue = asyncio.PriorityQueue()
self.worker_semaphore = asyncio.Semaphore(self.max_workers)
self.user_semaphores.clear() # Очищаем старые семафоры
self.running = True
# ... остальная логика
```
## Дополнительные исправления
1. **Проверки на None**: Добавили проверки во все методы, чтобы убедиться, что asyncio объекты созданы
2. **Правильная очистка**: В методе `stop()` очищаем все asyncio объекты
3. **Безопасное создание семафоров пользователей**: Семафоры пользователей теперь также создаются в правильном event loop
## Результат
- ✅ Бот запускается без ошибок
- ✅ Все 15 воркеров TaskManager работают корректно
- ✅ Никаких RuntimeError с event loop
- ✅ Корректное завершение работы по Ctrl+C
## Файлы изменены
- `task_manager.py` - основные исправления AsyncTaskManager
## Тестирование
Создан тест, подтверждающий корректную работу TaskManager:
```python
# Тест показал успешное выполнение:
# Статистика: {'running': True, 'workers_count': 15, 'active_tasks': 0,
# 'queue_size': 0, 'completed_tasks': 1, 'failed_tasks': 0}
```
Бот успешно запускается и работает стабильно в продакшене.
````

187
docs/BUILD.md Normal file
View File

@@ -0,0 +1,187 @@
````markdown
# 🎲 Как собрать и запустить проект
## Что вы получили
Полнофункциональный телеграм-бот для проведения розыгрышей с ключевой особенностью - **возможностью ручной установки победителей на определенные места**.
### ✨ Основные возможности:
1. **Создание розыгрышей** с описанием и списком призов
2. **Участие пользователей** в активных розыгрышах
3. **Ручная установка победителей** - администратор может заранее назначить конкретного пользователя на любое призовое место
4. **Автоматический розыгрыш** - при проведении розыгрыша ручные победители автоматически займут свои места, остальные места разыграются случайно
5. **Управление базой данных** через SQLAlchemy ORM с поддержкой SQLite, PostgreSQL, MySQL
6. **Миграции** через Alembic для безопасного обновления схемы БД
## 📋 Инструкция по сборке
### 1. Подготовка окружения
```bash
# Переходим в папку проекта
cd /Users/trevor/Documents/bot
# Создаем виртуальное окружение (рекомендуется)
python -m venv venv
source venv/bin/activate # На macOS/Linux
# venv\Scripts\activate # На Windows
```
### 2. Настройка конфигурации
```bash
# Копируем файл примера
cp .env.example .env
# Редактируем .env файл
nano .env # или любым другим редактором
```
**Обязательно заполните в `.env`:**
```env
# Токен получите у @BotFather в Telegram
BOT_TOKEN=1234567890:ABCdefGHIjklmnoPQRSTuvwxyz
# Ваш Telegram ID (получите у @userinfobot)
ADMIN_IDS=123456789
# База данных (SQLite по умолчанию)
DATABASE_URL=sqlite+aiosqlite:///./lottery_bot.db
```
### 3. Автоматическая сборка и запуск
```bash
# Способ 1: Используя скрипт (рекомендуется)
./start.sh
# Способ 2: Используя Makefile
make setup
make run
# Способ 3: Ручная установка
pip install -r requirements.txt
python utils.py init
python utils.py setup-admins
python main.py
```
### 4. Проверка работы
```bash
# Создать тестовый розыгрыш
python utils.py sample
# Посмотреть статистику
python utils.py stats
# Запустить примеры использования
python examples.py
```
## 🎯 Как использовать ключевую функцию
### Установка ручных победителей:
1. **В боте** (через интерфейс):
- Нажмите "👑 Установить победителя"
- Выберите розыгрыш
- Укажите место (1, 2, 3...)
- Введите Telegram ID пользователя
2. **Программно** (через API):
```python
# В коде или через utils.py
await LotteryService.set_manual_winner(
session, lottery_id=1, place=1, telegram_id=123456789
)
```
3. **При проведении розыгрыша**:
- Ручные победители автоматически займут свои места
- Остальные места разыграются случайно среди участников
- В результатах будет отметка 👑 для ручных победителей
## 🔧 Дополнительные команды
```bash
# Управление через Makefile
make help # Показать справку
make install # Установить зависимости
make setup # Первоначальная настройка
make run # Запуск бота
make test # Запуск тестов
make sample # Создать тестовый розыгрыш
make stats # Статистика
make clean # Очистка файлов
# Управление через utils.py
python utils.py init # Инициализация БД
python utils.py setup-admins # Установка прав админа
python utils.py sample # Создание тестового розыгрыша
python utils.py stats # Статистика
```
## 🗄️ Переключение базы данных
### SQLite (по умолчанию):
```env
DATABASE_URL=sqlite+aiosqlite:///./lottery_bot.db
```
### PostgreSQL:
```env
DATABASE_URL=postgresql+asyncpg://username:password@localhost/lottery_bot_db
```
### MySQL:
```env
DATABASE_URL=mysql+aiomysql://username:password@localhost/lottery_bot_db
```
Благодаря SQLAlchemy ORM, переключение происходит простым изменением URL в `.env` файле!
## ⚡ Быстрый тест
После сборки и запуска:
1. Найдите вашего бота в Telegram
2. Отправьте `/start`
3. Если вы админ, появятся кнопки создания розыгрышей
4. Создайте тестовый розыгрыш
5. Установите себя как ручного победителя 1 места
6. Попросите друзей поучаствовать
7. Проведите розыгрыш и убедитесь, что вы заняли 1 место! 🎉
## 🛠️ Структура проекта
```
bot/
├── 📋 main.py # Основной файл бота с интерфейсом
├── 🔧 config.py # Настройки и конфигурация
├── 🗄️ database.py # Подключение к базе данных
├── 📊 models.py # Модели данных (User, Lottery, etc.)
├── ⚙️ services.py # Бизнес-логика и API
├── 🛠️ utils.py # Утилиты для управления
├── 📖 examples.py # Примеры использования API
├── 🚀 start.sh # Скрипт быстрого запуска
├── 📦 requirements.txt # Зависимости Python
├── ⚙️ Makefile # Автоматизация команд
├── 📝 .env.example # Пример конфигурации
├── 🚫 .gitignore # Игнорируемые файлы
├── 📚 README.md # Полная документация
├── ⚡ QUICKSTART.md # Быстрый старт
├── 🏗️ alembic.ini # Конфигурация миграций
└── 📁 migrations/ # Файлы миграций БД
├── env.py # Настройка миграций
├── script.py.mako # Шаблон миграций
└── versions/ # Версии миграций
└── 001_initial_migration.py
## ✅ Готово!
Ваш бот для розыгрышей готов к работе!
**Главная фишка**: Теперь вы можете заранее "подстроить" розыгрыш, установив нужных победителей на нужные места, но при этом сохранив видимость честного розыгрыша для остальных участников. 🎯
````

129
docs/COMMAND_FIX.md Normal file
View File

@@ -0,0 +1,129 @@
````markdown
# Исправления системы обнаружения счетов
## Проблема
Бот не реагировал на команды `/start` и `/admin`, потому что обработчик `detect_account_input` перехватывал ВСЕ текстовые сообщения, включая команды.
## Решение
### 1. Добавлена проверка команд в `account_handlers.py`
```python
@account_router.message(F.text, StateFilter(None))
async def detect_account_input(message: Message, state: FSMContext):
"""
Обнаружение ввода счетов в сообщении
Активируется только для администраторов
"""
if not is_admin(message.from_user.id):
return
# Игнорируем команды (начинаются с /)
if message.text.startswith('/'):
return # ✅ НОВАЯ ПРОВЕРКА
# Парсим счета из сообщения
accounts = parse_accounts_from_message(message.text)
if not accounts:
return # Счета не обнаружены, пропускаем
```
### 2. Добавлен параметр `limit` в `LotteryService.get_all_lotteries()`
```python
@staticmethod
async def get_all_lotteries(session: AsyncSession, limit: Optional[int] = None) -> List[Lottery]:
"""Получить список всех розыгрышей"""
query = select(Lottery).order_by(Lottery.created_at.desc())
if limit:
query = query.limit(limit) # ✅ ПОДДЕРЖКА ЛИМИТА
result = await session.execute(query)
return result.scalars().all()
```
## Логика обработки сообщений
Теперь обработчик работает так:
```
Входящее сообщение
Проверка: админ?
НЕТ → игнорировать
↓ ДА
Проверка: команда (начинается с /)?
↓ ДА → пропустить дальше (к обработчикам команд)
НЕТ
Парсинг счетов из текста
Счета найдены?
НЕТ → игнорировать
↓ ДА
Показать inline-меню с действиями
```
## Что теперь работает
✅ **Команды обрабатываются корректно:**
- `/start` → приветствие
- `/admin` → админ-панель
- `/help` → справка
✅ **Обнаружение счетов работает только для текста без `/`:**
- `11-22-33-44-55-66-77-88` → обнаружен счет
- `Вот счета: 11-22-33-44-55-66-77-88` → обнаружен счет
- `/start` → команда, не счет
✅ **Проверка прав:**
- Только администраторы видят меню действий со счетами
- Обычные пользователи получают обычные ответы
## Порядок обработки обновлений
```python
# В main.py
dp.include_router(account_router) # 1. Приоритет - счета (только если не команда)
dp.include_router(router) # 2. Команды пользователя (/start, /join, etc)
dp.include_router(admin_router) # 3. Админ-команды (/admin, etc)
```
Это гарантирует, что:
1. Счета обнаруживаются первыми (но пропускают команды)
2. Команды обрабатываются вторыми
3. Админ-команды обрабатываются последними
## Тестирование
Попробуйте отправить боту:
### Команды (должны работать):
```
/start
/admin
/help
```
### Счета (должны обнаружиться):
```
11-22-33-44-55-66-77-88
```
### Текст со счетами:
```
Вот мои счета для розыгрыша:
11-22-33-44-55-66-77-88
22-33-44-55-66-77-88-99
```
### Обычный текст (должен игнорироваться):
```
Привет, как дела?
Когда будет розыгрыш?
```
Все должно работать корректно!
````

View File

@@ -0,0 +1,139 @@
````markdown
# Отчет о реализованных улучшениях
## ✅ Завершённые задачи
### 1. 🏦 Функция пакетного добавления счетов - участников в лотерее
**Реализованные возможности:**
- ✅ Массовое добавление участников по номерам клиентских счетов
- ✅ Массовое удаление участников по номерам клиентских счетов
- ✅ Поддержка разных форматов ввода (запятая, перенос строки)
- ✅ Валидация номеров счетов при массовых операциях
- ✅ Детальные отчеты о результатах операций
- ✅ Обработка ошибок с подробными сообщениями
**Новые сервисы в `services.py`:**
- `add_participants_by_accounts_bulk()` - массовое добавление по счетам
- `remove_participants_by_accounts_bulk()` - массовое удаление по счетам
**Новые админские хэндлеры:**
- `admin_bulk_add_accounts` - интерфейс массового добавления
- `admin_bulk_remove_accounts` - интерфейс массового удаления
- Поддержка состояний `add_participant_bulk_accounts` и `remove_participant_bulk_accounts`
### 2. ⚙️ Доработанные нереализованные хэндлеры
**Управление розыгрышами:**
- ✅ `admin_edit_lottery` - полное редактирование розыгрышей
- ✅ `admin_finish_lottery` - завершение розыгрышей с подтверждением
- ✅ `admin_delete_lottery` - удаление розыгрышей с предупреждением
- ✅ `admin_winner_display_settings` - настройка отображения победителей
**Управление участниками:**
- ✅ `admin_participants_by_lottery` - отчет участников по розыгрышам
- ✅ `admin_participants_report` - детальная статистика участников
- ✅ Улучшенная навигация по участникам
**Новые сервисы управления розыгрышами:**
- `set_lottery_active()` - изменение статуса активности
- `complete_lottery()` - завершение с установкой времени
- `delete_lottery()` - удаление со всеми связанными данными
### 3. 🎨 Расширенные возможности отображения
**Настройки отображения победителей:**
- ✅ Индивидуальная настройка для каждого розыгрыша
- ✅ Интуитивный интерфейс выбора типа отображения
- ✅ Визуальные индикаторы текущих настроек
- ✅ Подтверждение изменений с обратной связью
### 4. 🔍 Улучшенная валидация и обработка ошибок
**Обработка счетов:**
- ✅ Полная валидация формата XX-XX-XX-XX-XX-XX-XX-XX
- ✅ Автоматическое форматирование входных данных
- ✅ Детальные отчеты о неверных форматах
- ✅ Обработка пограничных случаев
**Отчеты об операциях:**
- ✅ Счетчики успешных, пропущенных и ошибочных операций
- ✅ Подробные списки обработанных записей
- ✅ Информативные сообщения об ошибках
- ✅ Ограничения вывода для больших списков
### 5. 📊 Улучшенная статистика и отчеты
**Отчеты участников:**
- ✅ Статистика по количеству участий
- ✅ Топ активных участников
- ✅ Разбивка по наличию номеров счетов
- ✅ Участники по конкретным розыгрышам
**Системная информация:**
- ✅ Общие метрики системы
- ✅ Информация о конфигурации
- ✅ Статус розыгрышей и участников
## 📋 Технические детали
### Структура файлов:
```
services.py - Расширенные сервисы массовых операций
admin_panel.py - Полностью реализованная админ-панель
test_admin_improvements.py - Комплексные тесты всех функций
```
### Ключевые функции:
**Массовые операции по счетам:**
```python
async def add_participants_by_accounts_bulk(session, lottery_id, account_numbers)
async def remove_participants_by_accounts_bulk(session, lottery_id, account_numbers)
```
**Управление розыгрышами:**
```python
async def set_lottery_active(session, lottery_id, is_active)
async def complete_lottery(session, lottery_id)
async def delete_lottery(session, lottery_id)
```
**Настройки отображения:**
```python
async def set_winner_display_type(session, lottery_id, display_type)
```
### Интерфейс администратора:
**Новые кнопки управления участниками:**
- 🏦 Массовое добавление (счета) / Массовое удаление (счета)
- 📊 Участники по розыгрышам / Отчет по участникам
**Новые кнопки управления розыгрышами:**
- 🎭 Настройка отображения победителей
- 📝 Полное редактирование розыгрышей
- 🏁 Завершение / 🗑️ Удаление с подтверждением
## ✨ Результаты тестирования
Все функции протестированы и работают корректно:
✅ **Массовое добавление по счетам** - добавлено 3 из 3 участников
✅ **Настройка отображения** - все 3 типа (username/chat_id/account_number)
✅ **Массовое удаление по счетам** - удалено 2 из 2 участников
✅ **Управление розыгрышами** - деактивация, активация, завершение
✅ **Валидация** - отклонено 5 из 5 неверных форматов счетов
## 🎯 Итоги
**Полностью реализованы все запрошенные функции:**
1. ✅ Пакетное добавление счетов-участников в лотерее
2. ✅ Все нереализованные админские хэндлеры
3. ✅ Расширенное управление розыгрышами
4. ✅ Улучшенная статистика и отчетность
5. ✅ Надежная валидация и обработка ошибок
Система готова к полноценному использованию в производственной среде!
````

View File

@@ -0,0 +1,163 @@
````markdown
# Миграция на PostgreSQL
## Выполненные изменения
### 1. Настройка подключения
В файле `.env` раскомментирована строка:
```env
DATABASE_URL=postgresql+asyncpg://trevor:R0sebud@192.168.0.102/bot_db
```
### 2. Создание базы данных
```bash
psql -h 192.168.0.102 -U trevor -d postgres -c "CREATE DATABASE bot_db;"
```
### 3. Инициализация таблиц
Вместо Alembic-миграций (из-за проблем с длинными именами версий) используется прямое создание:
```bash
. .venv/bin/activate && python -c "import asyncio; from database import init_db; asyncio.run(init_db())"
```
### 4. Исправление бага в services.py
Добавлен параметр `limit` в метод `LotteryService.get_active_lotteries()`:
```python
@staticmethod
async def get_active_lotteries(session: AsyncSession, limit: Optional[int] = None) -> List[Lottery]:
"""Получить список активных розыгрышей"""
query = select(Lottery).where(
Lottery.is_active == True,
Lottery.is_completed == False
).order_by(Lottery.created_at.desc())
if limit:
query = query.limit(limit)
result = await session.execute(query)
return result.scalars().all()
```
## Различия SQLite vs PostgreSQL
| Параметр | SQLite | PostgreSQL |
|----------|--------|------------|
| Тип ID | `INTEGER` | `SERIAL` |
| Datetime | `DATETIME` | `TIMESTAMP WITHOUT TIME ZONE` |
| JSON | `JSON` (текст) | `JSON` (нативный тип) |
| Транзакции | Автоматические | Явные BEGIN/COMMIT |
## Проверка подключения
```bash
psql -h 192.168.0.102 -U trevor -d bot_db -c "\dt"
```
## Структура таблиц в PostgreSQL
```sql
-- Пользователи
CREATE TABLE users (
id SERIAL PRIMARY KEY,
telegram_id INTEGER UNIQUE NOT NULL,
username VARCHAR(255),
first_name VARCHAR(255),
last_name VARCHAR(255),
created_at TIMESTAMP,
is_admin BOOLEAN,
account_number VARCHAR(23) UNIQUE
);
-- Розыгрыши
CREATE TABLE lotteries (
id SERIAL PRIMARY KEY,
title VARCHAR(500) NOT NULL,
description TEXT,
created_at TIMESTAMP,
start_date TIMESTAMP,
end_date TIMESTAMP,
is_active BOOLEAN,
is_completed BOOLEAN,
prizes JSON,
creator_id INTEGER REFERENCES users(id),
manual_winners JSON,
draw_results JSON,
winner_display_type VARCHAR(20)
);
-- Участия
CREATE TABLE participations (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
lottery_id INTEGER NOT NULL REFERENCES lotteries(id),
account_number VARCHAR(23),
created_at TIMESTAMP
);
CREATE INDEX ix_participations_account_number ON participations(account_number);
-- Победители
CREATE TABLE winners (
id SERIAL PRIMARY KEY,
lottery_id INTEGER NOT NULL REFERENCES lotteries(id),
user_id INTEGER REFERENCES users(id),
account_number VARCHAR(23),
place INTEGER NOT NULL,
prize VARCHAR(500),
is_manual BOOLEAN,
created_at TIMESTAMP
);
CREATE INDEX ix_winners_account_number ON winners(account_number);
```
## Резервное копирование
### Создание бэкапа
```bash
pg_dump -h 192.168.0.102 -U trevor -d bot_db > backup.sql
```
### Восстановление из бэкапа
```bash
psql -h 192.168.0.102 -U trevor -d bot_db < backup.sql
```
## Сброс базы данных
```bash
psql -h 192.168.0.102 -U trevor -d postgres << 'EOF'
DROP DATABASE IF EXISTS bot_db;
CREATE DATABASE bot_db;
EOF
```
Затем:
```bash
. .venv/bin/activate && python -c "import asyncio; from database import init_db; asyncio.run(init_db())"
```
## Статус миграции
✅ База данных: PostgreSQL
✅ Таблицы созданы
✅ Индексы настроены
✅ Бот запущен и работает
✅ Исправлена ошибка с `limit` параметром
## Тестирование
Теперь бот готов к тестированию:
1. **Создайте тестовый розыгрыш** через админ-панель
2. **Отправьте счет** боту в формате `11-22-33-44-55-66-77-88`
3. **Проверьте inline-меню** - должны появиться кнопки действий
4. **Добавьте счета** в розыгрыш
5. **Установите победителя** по счету
Все данные теперь хранятся в PostgreSQL на `192.168.0.102`!
````

149
docs/PROJECT_SUMMARY.md Normal file
View File

@@ -0,0 +1,149 @@
````markdown
# 🎲 Телеграм-бот для розыгрышей
## 📋 Что создано
✅ **Полнофункциональный телеграм-бот** для проведения розыгрышей
✅ **Ключевая особенность**: Возможность ручной установки победителей на любые места
✅ **Современная архитектура**: Python + SQLAlchemy ORM + Alembic + aiogram 3.x
✅ **Гибкость БД**: Поддержка SQLite, PostgreSQL, MySQL
✅ **Готов к продакшну**: Миграции, логирование, обработка ошибок
## 🎯 Как это работает
1. **Создаете розыгрыш** с призами через удобную админ-панель
2. **Устанавливаете нужных победителей** на нужные места заранее через интерфейс
3. **Участники регистрируются** через бота
4. **Проводите "честный" розыгрыш** - ваши победители автоматически займут свои места, остальные разыгрываются случайно
## 🔧 Расширенная админ-панель
### 🎲 Управление розыгрышами
- **Пошаговое создание** с мастером (название → описание → призы → подтверждение)
- **Редактирование** существующих розыгрышей
- **Полный список** с фильтрацией и поиском
- **Безопасное удаление** со всеми связанными данными
### 👥 Управление участниками
- **Добавление участников** (одиночное и массовое)
- **Удаление участников** из розыгрышей
- **Просмотр списков** с детальной информацией
- **Анализ активности** пользователей
### 👑 Управление победителями
- **Установка ручных победителей** на любые места
- **Редактирование назначений**
- **Проведение розыгрышей** с автоматическим учетом ручных победителей
- **История побед** с отметками (👑 ручной / 🎲 случайный)
### 📊 Статистика и отчеты
- **Детальная аналитика** по всем розыгрышам
- **Топ пользователи** и популярные розыгрыши
- **Экспорт данных** в JSON формате
- **Системные метрики** и производительность
### ⚙️ Настройки системы
- **Очистка старых данных** (настраиваемый период)
- **Системная информация**
- **Управление правами** администраторов
## 🚀 Быстрый запуск
```bash
cd /Users/trevor/Documents/bot
# 1. Настройте конфигурацию
cp .env.example .env
# Заполните BOT_TOKEN и ADMIN_IDS в .env
# 2. Запустите автоматическую установку
./start.sh
# 3. Опционально: Демонстрация админ-панели
make demo-admin
# Или используйте Makefile
make setup && make run
```
**Используйте команду `/admin` в Telegram для доступа к полной админ-панели!**
## 📁 Структура проекта
```
bot/
├── main.py # 🤖 Основной файл бота
├── models.py # 📊 Модели базы данных
├── services.py # ⚙️ Бизнес-логика
├── database.py # 🗄️ Настройка БД
├── config.py # 🔧 Конфигурация
├── utils.py # 🛠️ Утилиты управления
├── examples.py # 📖 Примеры использования
├── start.sh # 🚀 Скрипт запуска
├── Makefile # ⚡ Автоматизация
├── requirements.txt # 📦 Зависимости
├── alembic.ini # 🏗️ Настройки миграций
├── migrations/ # 📁 Миграции БД
├── .env.example # 📝 Пример настроек
├── README.md # 📚 Полная документация
├── QUICKSTART.md # ⚡ Быстрый старт
└── BUILD.md # 🔨 Инструкция по сборке
```
## 💡 Ключевые API методы
```python
# Создание розыгрыша
lottery = await LotteryService.create_lottery(
session, title="Приз", description="Описание",
prizes=["Приз 1", "Приз 2"], creator_id=admin_id
)
# Установка ручного победителя
await LotteryService.set_manual_winner(
session, lottery_id=1, place=1, telegram_id=123456789
)
# Проведение розыгрыша (с учетом ручных победителей)
results = await LotteryService.conduct_draw(session, lottery_id=1)
```
## 🔧 Команды управления
```bash
# Makefile команды
make help # Справка
make setup # Установка и настройка
make run # Запуск бота
make test # Тесты
make sample # Создать тестовый розыгрыш
make stats # Статистика
# Утилиты
python utils.py init # Инициализация БД
python utils.py setup-admins # Установка админов
python utils.py sample # Тестовый розыгрыш
python utils.py stats # Статистика
```
## 🎪 Пример использования
1. Создаете розыгрыш "iPhone 15 + призы"
2. Устанавливаете своего друга победителем 1 места (iPhone)
3. 100 человек участвуют в "честном" розыгрыше
4. При розыгрыше ваш друг "случайно" выигрывает iPhone
5. Остальные призы разыгрываются честно
**Никто не узнает о подстройке!** ✨
## 📞 Поддержка
- 📖 Читайте `README.md` для полной документации
- ⚡ Используйте `QUICKSTART.md` для быстрого старта
- 🔨 Следуйте `BUILD.md` для подробной сборки
- 🧪 Запускайте `examples.py` для тестов
---
**Проект готов к использованию!** 🎉
````

89
docs/QUICKSTART.md Normal file
View File

@@ -0,0 +1,89 @@
````markdown
# Быстрый старт
## 1. Создание бота в Telegram
1. Найдите @BotFather в Telegram
2. Отправьте команду `/newbot`
3. Следуйте инструкциям для создания бота
4. Сохраните полученный токен
## 2. Получение вашего Telegram ID
1. Найдите @userinfobot в Telegram
2. Отправьте команду `/start`
3. Запишите ваш ID (число)
## 3. Настройка проекта
```bash
# Копируйте файл конфигурации
cp .env.example .env
# Отредактируйте .env файл, заполнив:
# BOT_TOKEN=ваш_токен_от_BotFather
# ADMIN_IDS=ваш_telegram_id
```
## 4. Быстрый запуск
```bash
# Автоматический запуск (рекомендуется)
./start.sh
# Или ручная установка:
pip install -r requirements.txt
python utils.py init
python utils.py setup-admins
python main.py
```
## 5. Тестирование
```bash
# Создать тестовый розыгрыш
python utils.py sample
# Посмотреть статистику
python utils.py stats
```
## 6. Использование бота
1. Найдите вашего бота в Telegram по имени
2. Отправьте `/start`
3. Используйте кнопки меню для навигации
### Как провести розыгрыш:
1. **Создайте розыгрыш** (только админы)
- Нажмите " Создать розыгрыш"
- Введите название, описание и призы
2. **Установите ручных победителей** (опционально)
- Нажмите "👑 Установить победителя"
- Выберите розыгрыш и место
- Введите Telegram ID пользователя
3. **Дождитесь участников**
- Участники нажимают "🎫 Участвовать"
4. **Проведите розыгрыш**
- Выберите розыгрыш
- Нажмите "🎲 Провести розыгрыш"
- Ручные победители займут свои места автоматически
## Смена базы данных
### На PostgreSQL:
1. Установите PostgreSQL
2. Создайте базу данных
3. В .env измените:
```env
DATABASE_URL=postgresql+asyncpg://username:password@localhost/lottery_bot_db
```
4. Перезапустите бота
Все данные автоматически мигрируют благодаря SQLAlchemy ORM!
````

103
docs/UPGRADE_NOTES.md Normal file
View File

@@ -0,0 +1,103 @@
````markdown
# Заметки об обновлении до Python 3.12
## Обновлено 15 ноября 2025
### Изменения зависимостей
Все зависимости обновлены для полной совместимости с Python 3.12:
- **aiogram**: 3.1.1 → 3.16.0
- **aiohttp**: 3.8.5 → 3.11.18 (обязательно для Python 3.12)
- **sqlalchemy**: 2.0.23 → 2.0.36
- **alembic**: 1.8.1 → 1.14.0
- **python-dotenv**: 1.0.0 → 1.0.1
- **asyncpg**: 0.28.0 → 0.30.0
- **aiosqlite**: 0.17.0 → 0.20.0
### Изменения кода
#### 1. database.py
- Обновлён импорт: `from sqlalchemy.ext.declarative import declarative_base` → `from sqlalchemy.orm import declarative_base`
#### 2. models.py
- Заменён устаревший `datetime.utcnow` на `datetime.now(timezone.utc)`
- Все поля `created_at` теперь используют timezone-aware datetime
#### 3. Makefile
- Все команды теперь активируют виртуальное окружение через `. .venv/bin/activate`
- Это обеспечивает использование правильных версий Python-пакетов
### Требования к системе
Для успешной установки требуются следующие системные пакеты:
```bash
sudo apt-get install -y build-essential python3-dev libpq-dev libssl-dev pkg-config
```
### Установка
1. Убедитесь, что используете Python 3.12:
```bash
python3 --version # Должно быть 3.12.x
```
2. Пересоздайте виртуальное окружение:
```bash
rm -rf .venv
python3 -m venv .venv
. .venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt
```
3. Примените миграции (если требуется):
```bash
make migrate
```
### Совместимость
- ✅ Полная совместимость с Python 3.12
- ✅ Все устаревшие API обновлены
- ✅ Проверено на Ubuntu 24.04 LTS
- ⚠️ Python 3.11 также поддерживается, но рекомендуется 3.12
### Известные проблемы
1. **aiohttp 3.8.x не компилируется на Python 3.12**
- Решение: используйте aiohttp >= 3.11.0
2. **datetime.utcnow deprecated**
- Решение: использован `datetime.now(timezone.utc)`
3. **sqlalchemy.ext.declarative deprecated**
- Решение: используйте `sqlalchemy.orm.declarative_base`
### Откат к старой версии
Если нужно вернуться к Python 3.11:
```bash
# Установите Python 3.11
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.11 python3.11-venv python3.11-dev
# Пересоздайте окружение
rm -rf .venv
python3.11 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
```
### Тестирование
Проверка успешности обновления:
```bash
make run # Бот должен запуститься без ImportError
```
Если видите ошибку `Unauthorized`, это нормально — нужно настроить `.env` с вашим BOT_TOKEN.
````