Some checks reported errors
continuous-integration/drone/push Build encountered an error
Основные изменения: ✨ Новые функции: - Система регистрации пользователей с множественными счетами - Автоматическое подтверждение выигрышей через inline-кнопки - Механизм переигровки для неподтвержденных выигрышей (24 часа) - Подтверждение на уровне счетов (каждый счет подтверждается отдельно) - Скрипт полной очистки базы данных 🔧 Технические улучшения: - Исправлена ошибка MissingGreenlet при lazy loading (добавлен joinedload/selectinload) - Добавлено поле claimed_at для отслеживания времени подтверждения - Пакетное добавление счетов с выбором розыгрыша - Проверка владения конкретным счетом при подтверждении 📚 Документация: - docs/AUTO_CONFIRM_SYSTEM.md - Полная документация системы подтверждения - docs/ACCOUNT_BASED_CONFIRMATION.md - Подтверждение на уровне счетов - docs/REGISTRATION_SYSTEM.md - Система регистрации - docs/ADMIN_COMMANDS.md - Команды администратора - docs/CLEAR_DATABASE.md - Очистка БД - docs/QUICK_GUIDE.md - Быстрое начало - docs/UPDATE_LOG.md - Журнал обновлений 🗄️ База данных: - Миграция 003: Таблицы accounts, winner_verifications - Миграция 004: Поле claimed_at в таблице winners - Скрипт scripts/clear_database.py для полной очистки 🎮 Новые команды: Админские: - /check_unclaimed <lottery_id> - Проверка неподтвержденных выигрышей - /redraw <lottery_id> - Повторный розыгрыш - /add_accounts - Пакетное добавление счетов - /list_accounts <telegram_id> - Список счетов пользователя Пользовательские: - /register - Регистрация с вводом данных - /my_account - Просмотр своих счетов - Callback confirm_win_{id} - Подтверждение выигрыша 🛠️ Makefile: - make clear-db - Очистка всех данных из БД (с подтверждением) 🔒 Безопасность: - Проверка владения счетом при подтверждении - Защита от подтверждения чужих счетов - Независимое подтверждение каждого выигрышного счета 📊 Логика работы: 1. Пользователь регистрируется и добавляет счета 2. Счета участвуют в розыгрыше 3. Победители получают уведомление с кнопкой подтверждения 4. Каждый счет подтверждается отдельно (24 часа на подтверждение) 5. Неподтвержденные выигрыши переигрываются через /redraw
262 lines
9.4 KiB
Markdown
262 lines
9.4 KiB
Markdown
# Система регистрации и верификации выигрышей
|
||
|
||
## Архитектура
|
||
|
||
### Модели данных
|
||
|
||
#### 1. User (Расширенная)
|
||
- `club_card_number` - номер клубной карты (уникальный идентификатор клиента)
|
||
- `phone` - телефон для связи
|
||
- `is_registered` - прошел ли полную регистрацию
|
||
- `verification_code` - секретный код для подтверждения выигрыша (генерируется автоматически)
|
||
|
||
#### 2. Account (Новая)
|
||
- `account_number` - номер счета в формате XX-XX-XX-XX-XX-XX-XX
|
||
- `owner_id` - владелец счета (связь с User через club_card_number)
|
||
- `is_active` - активен ли счет
|
||
|
||
#### 3. WinnerVerification (Новая)
|
||
- `winner_id` - связь с Winner
|
||
- `verification_token` - токен для подтверждения выигрыша
|
||
- `is_verified` - подтвержден ли выигрыш
|
||
- `expires_at` - срок действия токена (24 часа)
|
||
|
||
## Процессы
|
||
|
||
### 1. Регистрация пользователя
|
||
|
||
**Инициатор:** Обычный пользователь через бота
|
||
|
||
**Шаги:**
|
||
1. Пользователь отправляет `/start`
|
||
2. Бот проверяет `is_registered`
|
||
3. Если `False` - запрашивает:
|
||
- Номер клубной карты
|
||
- Телефон (опционально)
|
||
4. Генерируется `verification_code` (8-символьный уникальный код)
|
||
5. Код показывается пользователю: "Ваш код верификации: **AB12CD34**. Сохраните его!"
|
||
6. `is_registered = True`
|
||
|
||
### 2. Создание счета администратором
|
||
|
||
**Инициатор:** Администратор
|
||
|
||
**Формат команды:**
|
||
```
|
||
/add_account 2223 11-22-33-44-55-66-77
|
||
```
|
||
|
||
**Процесс:**
|
||
1. Админ отправляет команду с номером КК и счетом
|
||
2. Бот находит пользователя по `club_card_number = 2223`
|
||
3. Создается запись в таблице `accounts`:
|
||
```python
|
||
Account(
|
||
account_number="11-22-33-44-55-66-77",
|
||
owner_id=user.id,
|
||
is_active=True
|
||
)
|
||
```
|
||
4. Пользователю отправляется уведомление:
|
||
```
|
||
✅ К вашему профилю добавлен счет:
|
||
11-22-33-44-55-66-77
|
||
```
|
||
|
||
### 3. Проведение розыгрыша с уведомлением победителей
|
||
|
||
**Процесс:**
|
||
1. Администратор проводит розыгрыш
|
||
2. Выбирается случайный счет (например, `11-22-33-44-55-66-77`)
|
||
3. Система ищет владельца счета:
|
||
```python
|
||
account = Account.query.filter_by(account_number="11-22-33-44-55-66-77").first()
|
||
user = account.owner if account else None
|
||
```
|
||
4. Создается запись `Winner` и `WinnerVerification`:
|
||
```python
|
||
winner = Winner(
|
||
lottery_id=lottery.id,
|
||
user_id=user.id if user else None,
|
||
account_number="11-22-33-44-55-66-77",
|
||
place=1,
|
||
prize="iPhone 15"
|
||
)
|
||
|
||
verification = WinnerVerification(
|
||
winner_id=winner.id,
|
||
verification_token=generate_token(),
|
||
expires_at=now + 24hours
|
||
)
|
||
```
|
||
|
||
5. Если `user` найден - отправляется личное сообщение:
|
||
```
|
||
🎉 ПОЗДРАВЛЯЕМ!
|
||
|
||
Вы выиграли 1 место в розыгрыше "Новогодний розыгрыш"!
|
||
🏆 Приз: iPhone 15
|
||
|
||
📋 Ваш выигрышный счет: 11-22-33-44-55-66-77
|
||
|
||
✅ Для подтверждения выигрыша:
|
||
1. Свяжитесь с администратором @admin_username
|
||
2. Сообщите ваш код верификации: AB12CD34
|
||
3. Администратор подтвердит ваш выигрыш в системе
|
||
|
||
⏰ Срок подтверждения: 24 часа
|
||
```
|
||
|
||
### 4. Верификация выигрыша администратором
|
||
|
||
**Сценарий:**
|
||
1. Победитель связывается с админом в личных сообщениях
|
||
2. Сообщает код верификации: `AB12CD34`
|
||
3. Админ проверяет код в боте:
|
||
```
|
||
/verify_winner AB12CD34 1
|
||
```
|
||
где `1` - ID розыгрыша
|
||
|
||
4. Система:
|
||
- Находит пользователя по `verification_code = "AB12CD34"`
|
||
- Проверяет, что у него есть выигрыш в розыгрыше #1
|
||
- Помечает `winner.is_claimed = True`
|
||
- Обновляет `verification.is_verified = True`
|
||
|
||
5. Победителю отправляется:
|
||
```
|
||
✅ Ваш выигрыш подтвержден!
|
||
|
||
Администратор свяжется с вами для получения приза.
|
||
```
|
||
|
||
## Дополнительные механизмы безопасности
|
||
|
||
### 1. Двухфакторная верификация (опционально)
|
||
Можно добавить отправку одноразового кода на телефон победителя.
|
||
|
||
### 2. Ограничение по времени
|
||
Токены верификации действуют 24 часа. После истечения срока требуется повторная генерация.
|
||
|
||
### 3. Логирование
|
||
Все действия с выигрышами логируются:
|
||
- Создание выигрыша
|
||
- Отправка уведомления
|
||
- Подтверждение администратором
|
||
- Получение приза
|
||
|
||
## API для админа
|
||
|
||
### Команды бота
|
||
|
||
#### `/add_account <club_card> <account_number>`
|
||
Добавить счет к профилю клиента
|
||
```
|
||
/add_account 2223 11-22-33-44-55-66-77
|
||
```
|
||
|
||
#### `/remove_account <account_number>`
|
||
Деактивировать счет
|
||
```
|
||
/remove_account 11-22-33-44-55-66-77
|
||
```
|
||
|
||
#### `/verify_winner <verification_code> <lottery_id>`
|
||
Подтвердить выигрыш победителя
|
||
```
|
||
/verify_winner AB12CD34 1
|
||
```
|
||
|
||
#### `/winner_status <lottery_id>`
|
||
Показать статус всех победителей розыгрыша
|
||
```
|
||
/winner_status 1
|
||
|
||
Результаты:
|
||
1 место - @username (КК: 2223) ✅ Подтвержден
|
||
2 место - Счет: 33-44-55-66-77-88-99 ⏳ Ожидает подтверждения
|
||
3 место - @user2 (КК: 4445) ❌ Не подтвержден (истек срок)
|
||
```
|
||
|
||
## Аналитика и отчеты
|
||
|
||
### Запросы для аналитики
|
||
|
||
```sql
|
||
-- Победители по клубным картам
|
||
SELECT
|
||
u.club_card_number,
|
||
u.first_name,
|
||
COUNT(w.id) as total_wins,
|
||
SUM(CASE WHEN w.is_claimed THEN 1 ELSE 0 END) as claimed_wins
|
||
FROM users u
|
||
JOIN winners w ON w.user_id = u.id
|
||
GROUP BY u.id;
|
||
|
||
-- Счета с наибольшим количеством участий
|
||
SELECT
|
||
a.account_number,
|
||
u.club_card_number,
|
||
COUNT(p.id) as participation_count
|
||
FROM accounts a
|
||
JOIN users u ON u.id = a.owner_id
|
||
JOIN participations p ON p.account_id = a.id
|
||
GROUP BY a.id, u.id
|
||
ORDER BY participation_count DESC;
|
||
|
||
-- Невостребованные выигрыши
|
||
SELECT
|
||
l.title,
|
||
w.place,
|
||
w.prize,
|
||
w.account_number,
|
||
u.club_card_number
|
||
FROM winners w
|
||
JOIN lotteries l ON l.id = w.lottery_id
|
||
LEFT JOIN users u ON u.id = w.user_id
|
||
WHERE w.is_claimed = false
|
||
AND w.created_at < NOW() - INTERVAL '24 hours';
|
||
```
|
||
|
||
## Миграция существующих данных
|
||
|
||
Если у вас уже есть данные в старой схеме:
|
||
|
||
```python
|
||
# Миграция старых account_number из users в таблицу accounts
|
||
async def migrate_accounts():
|
||
users = await session.execute(select(User).where(User.account_number != None))
|
||
for user in users.scalars():
|
||
account = Account(
|
||
account_number=user.account_number,
|
||
owner_id=user.id,
|
||
is_active=True
|
||
)
|
||
session.add(account)
|
||
user.account_number = None # Очищаем старое поле
|
||
await session.commit()
|
||
```
|
||
|
||
## Тестирование
|
||
|
||
### Сценарий 1: Полный цикл выигрыша
|
||
|
||
1. Регистрация пользователя (КК: 2223)
|
||
2. Админ добавляет счет: `/add_account 2223 11-22-33-44-55-66-77`
|
||
3. Счет участвует в розыгрыше
|
||
4. Счет выигрывает 1 место
|
||
5. Пользователю приходит уведомление с кодом
|
||
6. Пользователь связывается с админом, сообщает код
|
||
7. Админ подтверждает: `/verify_winner AB12CD34 1`
|
||
8. Выигрыш получен ✅
|
||
|
||
### Сценарий 2: Выигрыш незарегистрированного счета
|
||
|
||
1. Админ добавляет счет без владельца
|
||
2. Счет участвует и выигрывает
|
||
3. Бот показывает в публичном объявлении: "Счет 11-22-33-44-55-66-77 выиграл!"
|
||
4. Владелец счета регистрируется в боте
|
||
5. Админ привязывает счет к владельцу
|
||
6. Дальше стандартная процедура верификации
|