fix: исправлена обработка редактирования розыгрышей
All checks were successful
continuous-integration/drone/push Build is passing

- Добавлен обработчик handle_edit_field для admin_edit_field_{id}_{field} callbacks
- Исправлен toggle_lottery_active - теперь передаёт state вместо None
- Правильный парсинг lottery_id из позиции 3, а не с конца строки
- Обработка 'message is not modified' в bot_controller
- Модифицированы обработчики сообщений для поддержки редактирования
- Добавлен метод update_lottery в LotteryService
- Исправлены ошибки ValueError и AttributeError в меню редактирования
This commit is contained in:
2025-11-22 19:34:30 +09:00
parent 007274785f
commit ec8a23887d
4 changed files with 175 additions and 11 deletions

View File

@@ -138,7 +138,6 @@ clear-db:
else \
echo "❌ Отменено"; \
fi
# Очистка
clean:
@echo "🧹 Очистка временных файлов..."

View File

@@ -87,8 +87,21 @@ class BotController(IBotController):
is_registered=user.is_registered
)
await callback.message.edit_text(
text,
reply_markup=keyboard,
parse_mode="Markdown"
)
try:
await callback.message.edit_text(
text,
reply_markup=keyboard,
parse_mode="Markdown"
)
except Exception as e:
# Если сообщение не изменилось - просто отвечаем на callback
if "message is not modified" in str(e):
await callback.answer("✅ Уже показаны активные розыгрыши")
else:
# Другие ошибки - пробуем отправить новое сообщение
await callback.answer()
await callback.message.answer(
text,
reply_markup=keyboard,
parse_mode="Markdown"
)

View File

@@ -227,6 +227,25 @@ class LotteryService:
result = await session.execute(query)
return result.scalars().all()
@staticmethod
async def update_lottery(
session: AsyncSession,
lottery_id: int,
**updates
) -> bool:
"""Обновить данные розыгрыша"""
try:
await session.execute(
update(Lottery)
.where(Lottery.id == lottery_id)
.values(**updates)
)
await session.commit()
return True
except Exception:
await session.rollback()
return False
@staticmethod
async def get_all_lotteries(session: AsyncSession, limit: Optional[int] = None) -> List[Lottery]:

View File

@@ -236,11 +236,41 @@ async def start_create_lottery(callback: CallbackQuery, state: FSMContext):
@admin_router.message(StateFilter(AdminStates.lottery_title))
async def process_lottery_title(message: Message, state: FSMContext):
"""Обработка названия розыгрыша"""
"""Обработка названия розыгрыша (создание или редактирование)"""
if not is_admin(message.from_user.id):
await message.answer("❌ Недостаточно прав")
return
data = await state.get_data()
edit_lottery_id = data.get('edit_lottery_id')
# Если это редактирование существующего розыгрыша
if edit_lottery_id:
async with async_session_maker() as session:
success = await LotteryService.update_lottery(
session,
edit_lottery_id,
title=message.text
)
if success:
await message.answer(f"✅ Название изменено на: {message.text}")
await state.clear()
# Возвращаемся к выбору полей
from aiogram.types import CallbackQuery
fake_callback = CallbackQuery(
id="fake",
from_user=message.from_user,
chat_instance="fake",
data=f"admin_edit_lottery_select_{edit_lottery_id}",
message=message
)
await choose_edit_field(fake_callback, state)
else:
await message.answer("❌ Ошибка при изменении названия")
return
# Если это создание нового розыгрыша
await state.update_data(title=message.text)
text = f"📝 Создание нового розыгрыша\n\n"
@@ -254,11 +284,42 @@ async def process_lottery_title(message: Message, state: FSMContext):
@admin_router.message(StateFilter(AdminStates.lottery_description))
async def process_lottery_description(message: Message, state: FSMContext):
"""Обработка описания розыгрыша"""
"""Обработка описания розыгрыша (создание или редактирование)"""
if not is_admin(message.from_user.id):
await message.answer("❌ Недостаточно прав")
return
data = await state.get_data()
edit_lottery_id = data.get('edit_lottery_id')
# Если это редактирование существующего розыгрыша
if edit_lottery_id:
description = None if message.text == "-" else message.text
async with async_session_maker() as session:
success = await LotteryService.update_lottery(
session,
edit_lottery_id,
description=description
)
if success:
await message.answer(f"✅ Описание изменено")
await state.clear()
# Возвращаемся к выбору полей
from aiogram.types import CallbackQuery
fake_callback = CallbackQuery(
id="fake",
from_user=message.from_user,
chat_instance="fake",
data=f"admin_edit_lottery_select_{edit_lottery_id}",
message=message
)
await choose_edit_field(fake_callback, state)
else:
await message.answer("❌ Ошибка при изменении описания")
return
# Если это создание нового розыгрыша
description = None if message.text == "-" else message.text
await state.update_data(description=description)
@@ -281,12 +342,43 @@ async def process_lottery_description(message: Message, state: FSMContext):
@admin_router.message(StateFilter(AdminStates.lottery_prizes))
async def process_lottery_prizes(message: Message, state: FSMContext):
"""Обработка призов розыгрыша"""
"""Обработка призов розыгрыша (создание или редактирование)"""
if not is_admin(message.from_user.id):
await message.answer("❌ Недостаточно прав")
return
data = await state.get_data()
edit_lottery_id = data.get('edit_lottery_id')
prizes = [prize.strip() for prize in message.text.split('\n') if prize.strip()]
# Если это редактирование существующего розыгрыша
if edit_lottery_id:
async with async_session_maker() as session:
success = await LotteryService.update_lottery(
session,
edit_lottery_id,
prizes=prizes
)
if success:
await message.answer(f"✅ Призы изменены")
await state.clear()
# Возвращаемся к выбору полей
from aiogram.types import CallbackQuery
fake_callback = CallbackQuery(
id="fake",
from_user=message.from_user,
chat_instance="fake",
data=f"admin_edit_lottery_select_{edit_lottery_id}",
message=message
)
await choose_edit_field(fake_callback, state)
else:
await message.answer("❌ Ошибка при изменении призов")
return
# Если это создание нового розыгрыша
await state.update_data(prizes=prizes)
data = await state.get_data()
@@ -1775,8 +1867,49 @@ async def choose_edit_field(callback: CallbackQuery, state: FSMContext):
await callback.message.edit_text(text, reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons))
@admin_router.callback_query(F.data.startswith("admin_edit_field_"))
async def handle_edit_field(callback: CallbackQuery, state: FSMContext):
"""Обработка выбора поля для редактирования"""
if not is_admin(callback.from_user.id):
await callback.answer("❌ Недостаточно прав", show_alert=True)
return
# Парсим callback_data: admin_edit_field_{lottery_id}_{field_name}
parts = callback.data.split("_")
if len(parts) < 5:
await callback.answer("❌ Неверный формат данных", show_alert=True)
return
lottery_id = int(parts[3]) # admin_edit_field_{lottery_id}_...
field_name = "_".join(parts[4:]) # Всё после lottery_id это имя поля
await state.update_data(edit_lottery_id=lottery_id, edit_field=field_name)
# Определяем, что редактируем
if field_name == "title":
text = "📝 Введите новое название розыгрыша:"
await state.set_state(AdminStates.lottery_title)
elif field_name == "description":
text = "📄 Введите новое описание розыгрыша:"
await state.set_state(AdminStates.lottery_description)
elif field_name == "prizes":
text = "🎁 Введите новый список призов (каждый приз с новой строки):"
await state.set_state(AdminStates.lottery_prizes)
else:
await callback.answer("❌ Неизвестное поле", show_alert=True)
return
await callback.message.edit_text(
text,
reply_markup=InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="❌ Отмена", callback_data="admin_lotteries")]
])
)
await callback.answer()
@admin_router.callback_query(F.data.startswith("admin_toggle_active_"))
async def toggle_lottery_active(callback: CallbackQuery):
async def toggle_lottery_active(callback: CallbackQuery, state: FSMContext):
"""Переключить активность розыгрыша"""
if not is_admin(callback.from_user.id):
await callback.answer("❌ Недостаточно прав", show_alert=True)
@@ -1798,7 +1931,7 @@ async def toggle_lottery_active(callback: CallbackQuery):
await callback.answer("❌ Ошибка изменения статуса", show_alert=True)
# Обновляем отображение
await choose_edit_field(callback, None)
await choose_edit_field(callback, state)
@admin_router.callback_query(F.data == "admin_finish_lottery")