refactor
This commit is contained in:
3
src/display/__init__.py
Normal file
3
src/display/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Компоненты отображения и вывода результатов.
|
||||
"""
|
||||
102
src/display/conduct_draw.py
Normal file
102
src/display/conduct_draw.py
Normal file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Скрипт для проведения розыгрыша
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
from ..core.database import async_session_maker
|
||||
from ..core.services import LotteryService, ParticipationService
|
||||
from ..core.models import Lottery, User
|
||||
|
||||
async def conduct_lottery_draw(lottery_id: int):
|
||||
"""Проводим розыгрыш для указанного ID"""
|
||||
print(f"🎲 Проведение розыгрыша #{lottery_id}")
|
||||
|
||||
async with async_session_maker() as session:
|
||||
# Получаем розыгрыш
|
||||
lottery = await LotteryService.get_lottery(session, lottery_id)
|
||||
if not lottery:
|
||||
print(f"❌ Розыгрыш {lottery_id} не найден")
|
||||
return
|
||||
|
||||
print(f"📋 Розыгрыш: {lottery.title}")
|
||||
|
||||
# Призы уже загружены как список
|
||||
prizes = lottery.prizes if isinstance(lottery.prizes, list) else json.loads(lottery.prizes)
|
||||
print(f"🏆 Призы: {len(prizes)} шт.")
|
||||
|
||||
# Получаем участников
|
||||
participants = await ParticipationService.get_participants(session, lottery_id)
|
||||
print(f"👥 Участников: {len(participants)}")
|
||||
|
||||
if len(participants) == 0:
|
||||
print("⚠️ Нет участников для розыгрыша")
|
||||
return
|
||||
|
||||
# Выводим список участников
|
||||
print("\n👥 Список участников:")
|
||||
for i, user in enumerate(participants, 1):
|
||||
accounts = user.account_number.split(',') if user.account_number else ['Нет счетов']
|
||||
print(f" {i}. {user.first_name} (@{user.username}) - {len(accounts)} счет(ов)")
|
||||
|
||||
# Проводим розыгрыш
|
||||
print(f"\n🎲 Проводим розыгрыш...")
|
||||
|
||||
# Используем метод из LotteryService
|
||||
try:
|
||||
winners = await LotteryService.conduct_draw(session, lottery_id)
|
||||
|
||||
if winners:
|
||||
print(f"\n🎉 Победители определены:")
|
||||
for i, winner_data in enumerate(winners, 1):
|
||||
user = winner_data['user']
|
||||
prize = winner_data['prize']
|
||||
print(f" 🏆 {i} место: {user.first_name} (@{user.username})")
|
||||
print(f" 💎 Приз: {prize}")
|
||||
|
||||
# Обновляем статус розыгрыша
|
||||
await LotteryService.set_lottery_completed(session, lottery_id, True)
|
||||
print(f"\n✅ Розыгрыш завершен и помечен как завершенный")
|
||||
|
||||
else:
|
||||
print("❌ Ошибка при проведении розыгрыша")
|
||||
|
||||
except Exception as e:
|
||||
print(f"💥 Ошибка: {e}")
|
||||
|
||||
async def main():
|
||||
"""Главная функция"""
|
||||
print("🎯 Скрипт проведения розыгрышей")
|
||||
print("=" * 50)
|
||||
|
||||
# Показываем доступные розыгрыши
|
||||
async with async_session_maker() as session:
|
||||
lotteries = await LotteryService.get_active_lotteries(session)
|
||||
|
||||
if not lotteries:
|
||||
print("❌ Нет активных розыгрышей")
|
||||
return
|
||||
|
||||
print("🎲 Активные розыгрыши:")
|
||||
for lottery in lotteries:
|
||||
participants = await ParticipationService.get_participants(session, lottery.id)
|
||||
print(f" {lottery.id}. {lottery.title} ({len(participants)} участников)")
|
||||
|
||||
# Просим выбрать розыгрыш
|
||||
print("\nВведите ID розыгрыша для проведения (или 'all' для всех):")
|
||||
choice = input("> ").strip().lower()
|
||||
|
||||
if choice == 'all':
|
||||
# Проводим все розыгрыши
|
||||
for lottery in lotteries:
|
||||
await conduct_lottery_draw(lottery.id)
|
||||
print("-" * 30)
|
||||
else:
|
||||
try:
|
||||
lottery_id = int(choice)
|
||||
await conduct_lottery_draw(lottery_id)
|
||||
except ValueError:
|
||||
print("❌ Неверный ID розыгрыша")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
191
src/display/demo_admin.py
Normal file
191
src/display/demo_admin.py
Normal file
@@ -0,0 +1,191 @@
|
||||
"""
|
||||
Демонстрация возможностей админ-панели
|
||||
"""
|
||||
import asyncio
|
||||
from ..core.database import async_session_maker, init_db
|
||||
from ..core.services import UserService, LotteryService
|
||||
from ..utils.admin_utils import AdminUtils, ReportGenerator
|
||||
|
||||
|
||||
async def demo_admin_features():
|
||||
"""Демонстрация функций админ-панели"""
|
||||
print("🚀 Демонстрация возможностей админ-панели")
|
||||
print("=" * 50)
|
||||
|
||||
await init_db()
|
||||
|
||||
async with async_session_maker() as session:
|
||||
# Создаем тестового администратора
|
||||
admin = await UserService.get_or_create_user(
|
||||
session,
|
||||
telegram_id=123456789,
|
||||
username="admin",
|
||||
first_name="Администратор",
|
||||
last_name="Системы"
|
||||
)
|
||||
await UserService.set_admin(session, 123456789, True)
|
||||
print(f"✅ Создан администратор: {admin.first_name}")
|
||||
|
||||
# Создаем тестовых пользователей
|
||||
users = []
|
||||
for i in range(1, 11):
|
||||
user = await UserService.get_or_create_user(
|
||||
session,
|
||||
telegram_id=200000000 + i,
|
||||
username=f"user{i}",
|
||||
first_name=f"Пользователь{i}",
|
||||
last_name="Тестовый"
|
||||
)
|
||||
users.append(user)
|
||||
print(f"✅ Создано {len(users)} тестовых пользователей")
|
||||
|
||||
# Создаем несколько розыгрышей
|
||||
lottery1 = await LotteryService.create_lottery(
|
||||
session,
|
||||
title="🎉 Новогодний мега-розыгрыш",
|
||||
description="Грандиозный розыгрыш к Новому году с невероятными призами!",
|
||||
prizes=[
|
||||
"🥇 iPhone 15 Pro Max 1TB",
|
||||
"🥈 MacBook Air M2 13\"",
|
||||
"🥉 iPad Pro 12.9\"",
|
||||
"🏆 AirPods Pro 2",
|
||||
"🎁 Подарочная карта Apple 50,000₽"
|
||||
],
|
||||
creator_id=admin.id
|
||||
)
|
||||
|
||||
lottery2 = await LotteryService.create_lottery(
|
||||
session,
|
||||
title="🚗 Автомобильный розыгрыш",
|
||||
description="Выиграй автомобиль своей мечты!",
|
||||
prizes=[
|
||||
"🥇 Tesla Model 3",
|
||||
"🥈 BMW X3",
|
||||
"🥉 Mercedes-Benz C-Class"
|
||||
],
|
||||
creator_id=admin.id
|
||||
)
|
||||
|
||||
lottery3 = await LotteryService.create_lottery(
|
||||
session,
|
||||
title="🏖️ Отпуск мечты",
|
||||
description="Путешествие в райские места",
|
||||
prizes=[
|
||||
"🥇 Тур на Мальдивы на двоих",
|
||||
"🥈 Неделя в Дубае",
|
||||
"🥉 Тур в Турцию"
|
||||
],
|
||||
creator_id=admin.id
|
||||
)
|
||||
|
||||
print(f"✅ Создано 3 розыгрыша:")
|
||||
print(f" - {lottery1.title}")
|
||||
print(f" - {lottery2.title}")
|
||||
print(f" - {lottery3.title}")
|
||||
|
||||
# Добавляем участников в розыгрыши
|
||||
participants_added = 0
|
||||
for user in users:
|
||||
# В первый розыгрыш добавляем всех
|
||||
if await LotteryService.add_participant(session, lottery1.id, user.id):
|
||||
participants_added += 1
|
||||
|
||||
# Во второй - половину
|
||||
if user.id % 2 == 0:
|
||||
if await LotteryService.add_participant(session, lottery2.id, user.id):
|
||||
participants_added += 1
|
||||
|
||||
# В третий - треть
|
||||
if user.id % 3 == 0:
|
||||
if await LotteryService.add_participant(session, lottery3.id, user.id):
|
||||
participants_added += 1
|
||||
|
||||
print(f"✅ Добавлено {participants_added} участий")
|
||||
|
||||
# Устанавливаем предопределенных победителей
|
||||
print("\n👑 Установка предопределенных победителей:")
|
||||
|
||||
# В первом розыгрыше: 1 и 3 места
|
||||
await LotteryService.set_manual_winner(session, lottery1.id, 1, users[0].telegram_id)
|
||||
await LotteryService.set_manual_winner(session, lottery1.id, 3, users[2].telegram_id)
|
||||
print(f" 🎯 {lottery1.title}: 1 место - {users[0].first_name}, 3 место - {users[2].first_name}")
|
||||
|
||||
# Во втором розыгрыше: только 1 место
|
||||
await LotteryService.set_manual_winner(session, lottery2.id, 1, users[1].telegram_id)
|
||||
print(f" 🚗 {lottery2.title}: 1 место - {users[1].first_name}")
|
||||
|
||||
# Получаем статистику по розыгрышам
|
||||
print(f"\n📊 Статистика по розыгрышам:")
|
||||
for lottery in [lottery1, lottery2, lottery3]:
|
||||
stats = await AdminUtils.get_lottery_statistics(session, lottery.id)
|
||||
print(f" 🎲 {lottery.title}:")
|
||||
print(f" Участников: {stats['participants_count']}")
|
||||
print(f" Ручных победителей: {len(lottery.manual_winners or {})}")
|
||||
|
||||
# Проводим розыгрыши
|
||||
print(f"\n🎲 Проведение розыгрышей:")
|
||||
|
||||
# Первый розыгрыш
|
||||
results1 = await LotteryService.conduct_draw(session, lottery1.id)
|
||||
print(f" 🎉 {lottery1.title} - результаты:")
|
||||
for place, winner_info in results1.items():
|
||||
user = winner_info['user']
|
||||
manual = " 👑" if winner_info['is_manual'] else " 🎲"
|
||||
print(f" {place}. {user.first_name}{manual}")
|
||||
|
||||
# Второй розыгрыш
|
||||
results2 = await LotteryService.conduct_draw(session, lottery2.id)
|
||||
print(f" 🚗 {lottery2.title} - результаты:")
|
||||
for place, winner_info in results2.items():
|
||||
user = winner_info['user']
|
||||
manual = " 👑" if winner_info['is_manual'] else " 🎲"
|
||||
print(f" {place}. {user.first_name}{manual}")
|
||||
|
||||
# Генерируем отчет
|
||||
print(f"\n📋 Генерация отчета:")
|
||||
report = await ReportGenerator.generate_summary_report(session)
|
||||
print(report)
|
||||
|
||||
# Экспорт данных
|
||||
print(f"💾 Экспорт данных первого розыгрыша:")
|
||||
export_data = await AdminUtils.export_lottery_data(session, lottery1.id)
|
||||
print(f" ✅ Экспортировано:")
|
||||
print(f" - Розыгрыш: {export_data['lottery']['title']}")
|
||||
print(f" - Участников: {len(export_data['participants'])}")
|
||||
print(f" - Победителей: {len(export_data['winners'])}")
|
||||
|
||||
# Активность пользователя
|
||||
print(f"\n👤 Активность пользователя {users[0].first_name}:")
|
||||
activity = await AdminUtils.get_user_activity(session, users[0].telegram_id)
|
||||
print(f" 📊 Статистика:")
|
||||
print(f" Участий: {activity['total_participations']}")
|
||||
print(f" Побед: {activity['total_wins']}")
|
||||
|
||||
print(f"\n" + "=" * 50)
|
||||
print(f"✅ Демонстрация завершена!")
|
||||
print(f"")
|
||||
print(f"🎯 Что показано:")
|
||||
print(f" ✅ Создание пользователей и розыгрышей")
|
||||
print(f" ✅ Добавление участников")
|
||||
print(f" ✅ Установка предопределенных победителей")
|
||||
print(f" ✅ Проведение розыгрышей с ручными победителями")
|
||||
print(f" ✅ Генерация статистики и отчетов")
|
||||
print(f" ✅ Экспорт данных")
|
||||
print(f" ✅ Анализ активности пользователей")
|
||||
print(f"")
|
||||
print(f"🚀 Админ-панель готова к использованию!")
|
||||
|
||||
# Показываем ключевую особенность
|
||||
print(f"\n🎯 КЛЮЧЕВАЯ ОСОБЕННОСТЬ:")
|
||||
print(f"В первом розыгрыше мы заранее установили:")
|
||||
print(f" 👑 1 место: {users[0].first_name}")
|
||||
print(f" 👑 3 место: {users[2].first_name}")
|
||||
print(f"")
|
||||
print(f"При розыгрыше эти пользователи автоматически заняли свои места,")
|
||||
print(f"а остальные места (2, 4, 5) были разыграны случайно!")
|
||||
print(f"")
|
||||
print(f"🎭 Никто из участников не знает о подстройке!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(demo_admin_features())
|
||||
32
src/display/simple_draw.py
Normal file
32
src/display/simple_draw.py
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Простой скрипт для проведения розыгрыша
|
||||
"""
|
||||
import asyncio
|
||||
from ..core.database import async_session_maker
|
||||
from ..core.services import LotteryService
|
||||
|
||||
async def conduct_simple_draw():
|
||||
"""Проводим розыгрыш"""
|
||||
print("🎲 Проведение розыгрыша")
|
||||
print("=" * 30)
|
||||
|
||||
lottery_id = 1 # Первый розыгрыш
|
||||
|
||||
async with async_session_maker() as session:
|
||||
print(f"🎯 Проводим розыгрыш #{lottery_id}")
|
||||
|
||||
try:
|
||||
# Проводим розыгрыш
|
||||
winners = await LotteryService.conduct_draw(session, lottery_id)
|
||||
|
||||
print(f"🎉 Розыгрыш проведен!")
|
||||
print(f"📊 Результат: {winners}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(conduct_simple_draw())
|
||||
116
src/display/winner_display.py
Normal file
116
src/display/winner_display.py
Normal file
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
Утилиты для отображения информации о победителях в зависимости от настроек розыгрыша
|
||||
"""
|
||||
from typing import Dict, Any, Optional
|
||||
from ..core.models import User, Lottery
|
||||
from ..utils.account_utils import mask_account_number
|
||||
|
||||
|
||||
def format_winner_display(user: User, lottery: Lottery, show_sensitive_data: bool = False) -> str:
|
||||
"""
|
||||
Форматирует отображение победителя в зависимости от настроек розыгрыша
|
||||
|
||||
Args:
|
||||
user: Пользователь-победитель
|
||||
lottery: Розыгрыш
|
||||
show_sensitive_data: Показывать ли чувствительные данные (для админов)
|
||||
|
||||
Returns:
|
||||
str: Отформатированная строка для отображения победителя
|
||||
"""
|
||||
display_type = getattr(lottery, 'winner_display_type', 'username')
|
||||
|
||||
if display_type == 'username':
|
||||
# Отображаем username или имя
|
||||
if user.username:
|
||||
return f"@{user.username}"
|
||||
else:
|
||||
return user.first_name or f"Пользователь {user.id}"
|
||||
|
||||
elif display_type == 'chat_id':
|
||||
# Отображаем Telegram ID
|
||||
return f"ID: {user.telegram_id}"
|
||||
|
||||
elif display_type == 'account_number':
|
||||
# Отображаем номер клиентского счета
|
||||
if not user.account_number:
|
||||
return "Счёт не указан"
|
||||
|
||||
if show_sensitive_data:
|
||||
# Для админов показываем полный номер
|
||||
return f"Счёт: {user.account_number}"
|
||||
else:
|
||||
# Для публичного показа маскируем номер
|
||||
masked = mask_account_number(user.account_number, show_last_digits=4)
|
||||
return f"Счёт: {masked}"
|
||||
|
||||
else:
|
||||
# Fallback к username/имени
|
||||
if user.username:
|
||||
return f"@{user.username}"
|
||||
else:
|
||||
return user.first_name or f"Пользователь {user.id}"
|
||||
|
||||
|
||||
def format_winner_info(winner_data: Dict[str, Any], show_sensitive_data: bool = False) -> str:
|
||||
"""
|
||||
Форматирует информацию о победителе из данных розыгрыша
|
||||
|
||||
Args:
|
||||
winner_data: Словарь с данными о победителе
|
||||
show_sensitive_data: Показывать ли чувствительные данные
|
||||
|
||||
Returns:
|
||||
str: Отформатированная строка для отображения
|
||||
"""
|
||||
user = winner_data.get('user')
|
||||
place = winner_data.get('place', 1)
|
||||
prize = winner_data.get('prize', f'Приз {place} места')
|
||||
|
||||
if not user:
|
||||
return f"{place}. Победитель не определен"
|
||||
|
||||
# Пробуем получить lottery из winner_data, если есть
|
||||
lottery = winner_data.get('lottery')
|
||||
|
||||
if lottery:
|
||||
winner_display = format_winner_display(user, lottery, show_sensitive_data)
|
||||
else:
|
||||
# Fallback если нет данных о розыгрыше
|
||||
if user.username:
|
||||
winner_display = f"@{user.username}"
|
||||
else:
|
||||
winner_display = user.first_name or f"Пользователь {user.id}"
|
||||
|
||||
return f"{place}. {winner_display}"
|
||||
|
||||
|
||||
def get_display_type_name(display_type: str) -> str:
|
||||
"""
|
||||
Получить человекочитаемое название типа отображения
|
||||
|
||||
Args:
|
||||
display_type: Тип отображения
|
||||
|
||||
Returns:
|
||||
str: Название типа
|
||||
"""
|
||||
types = {
|
||||
'username': 'Username/Имя',
|
||||
'chat_id': 'Telegram ID',
|
||||
'account_number': 'Номер счёта'
|
||||
}
|
||||
return types.get(display_type, 'Неизвестно')
|
||||
|
||||
|
||||
def validate_display_type(display_type: str) -> bool:
|
||||
"""
|
||||
Проверяет корректность типа отображения
|
||||
|
||||
Args:
|
||||
display_type: Тип отображения для проверки
|
||||
|
||||
Returns:
|
||||
bool: True если тип корректен
|
||||
"""
|
||||
return display_type in ['username', 'chat_id', 'account_number']
|
||||
Reference in New Issue
Block a user