import logging from aiogram import Dispatcher, types, F from aiogram.fsm.context import FSMContext from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.states import AdminStates from app.database.models import User from app.localization.texts import get_texts from app.utils.decorators import admin_required, error_handler from app.utils.validators import validate_html_tags, get_html_help_text from app.database.crud.rules import get_current_rules_content, create_or_update_rules, clear_all_rules logger = logging.getLogger(__name__) @admin_required @error_handler async def show_rules_management( callback: types.CallbackQuery, db_user: User, db: AsyncSession ): text = """ 📋 Управление правилами сервиса Текущие правила показываются пользователям при регистрации и в главном меню. Выберите действие: """ keyboard = [ [types.InlineKeyboardButton(text="📝 Редактировать правила", callback_data="admin_edit_rules")], [types.InlineKeyboardButton(text="👀 Просмотр правил", callback_data="admin_view_rules")], [types.InlineKeyboardButton(text="🗑️ Очистить правила", callback_data="admin_clear_rules")], [types.InlineKeyboardButton(text="ℹ️ Помощь по HTML", callback_data="admin_rules_help")], [types.InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_submenu_settings")] ] await callback.message.edit_text( text, reply_markup=types.InlineKeyboardMarkup(inline_keyboard=keyboard) ) await callback.answer() @admin_required @error_handler async def view_current_rules( callback: types.CallbackQuery, db_user: User, db: AsyncSession ): try: current_rules = await get_current_rules_content(db, db_user.language) is_valid, error_msg = validate_html_tags(current_rules) warning = "" if not is_valid: warning = f"\n\n⚠️ Внимание: В правилах найдена ошибка HTML: {error_msg}" await callback.message.edit_text( f"📋 Текущие правила сервиса\n\n{current_rules}{warning}", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="✏️ Редактировать", callback_data="admin_edit_rules")], [types.InlineKeyboardButton(text="🗑️ Очистить", callback_data="admin_clear_rules")], [types.InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_rules")] ]) ) await callback.answer() except Exception as e: logger.error(f"Ошибка при показе правил: {e}") await callback.message.edit_text( "❌ Ошибка при загрузке правил. Возможно, в тексте есть некорректные HTML теги.", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="🗑️ Очистить правила", callback_data="admin_clear_rules")], [types.InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_rules")] ]) ) await callback.answer() @admin_required @error_handler async def start_edit_rules( callback: types.CallbackQuery, db_user: User, state: FSMContext, db: AsyncSession ): try: current_rules = await get_current_rules_content(db, db_user.language) preview = current_rules[:500] + ('...' if len(current_rules) > 500 else '') text = ( "✏️ Редактирование правил\n\n" f"Текущие правила:\n{preview}\n\n" "Отправьте новый текст правил сервиса.\n\n" "Поддерживается HTML разметка. Все теги будут проверены перед сохранением.\n\n" "💡 Совет: Нажмите /html_help для просмотра поддерживаемых тегов" ) await callback.message.edit_text( text, reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="ℹ️ HTML помощь", callback_data="admin_rules_help")], [types.InlineKeyboardButton(text="❌ Отмена", callback_data="admin_rules")] ]) ) await state.set_state(AdminStates.editing_rules_page) await callback.answer() except Exception as e: logger.error(f"Ошибка при начале редактирования правил: {e}") await callback.answer("❌ Ошибка при загрузке правил для редактирования", show_alert=True) @admin_required @error_handler async def process_rules_edit( message: types.Message, db_user: User, state: FSMContext, db: AsyncSession ): new_rules = message.text if len(new_rules) > 4000: await message.answer("❌ Текст правил слишком длинный (максимум 4000 символов)") return is_valid, error_msg = validate_html_tags(new_rules) if not is_valid: await message.answer( f"❌ Ошибка в HTML разметке:\n{error_msg}\n\n" f"Пожалуйста, исправьте ошибки и отправьте текст заново.\n\n" f"💡 Используйте /html_help для просмотра правильного синтаксиса", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="ℹ️ HTML помощь", callback_data="admin_rules_help")], [types.InlineKeyboardButton(text="❌ Отмена", callback_data="admin_rules")] ]) ) return try: preview_text = f"📋 Предварительный просмотр новых правил:\n\n{new_rules}\n\n" preview_text += f"⚠️ Внимание! Новые правила будут показываться всем пользователям.\n\n" preview_text += f"Сохранить изменения?" if len(preview_text) > 4000: preview_text = ( "📋 Предварительный просмотр новых правил:\n\n" f"{new_rules[:500]}...\n\n" f"⚠️ Внимание! Новые правила будут показываться всем пользователям.\n\n" f"Текст правил: {len(new_rules)} символов\n" f"Сохранить изменения?" ) await message.answer( preview_text, reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [ types.InlineKeyboardButton(text="✅ Сохранить", callback_data="admin_save_rules"), types.InlineKeyboardButton(text="❌ Отмена", callback_data="admin_rules") ] ]) ) await state.update_data(new_rules=new_rules) except Exception as e: logger.error(f"Ошибка при показе превью правил: {e}") await message.answer( "⚠️ Подтверждение сохранения правил\n\n" f"Новые правила готовы к сохранению ({len(new_rules)} символов).\n" f"HTML теги проверены и корректны.\n\n" f"Сохранить изменения?", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [ types.InlineKeyboardButton(text="✅ Сохранить", callback_data="admin_save_rules"), types.InlineKeyboardButton(text="❌ Отмена", callback_data="admin_rules") ] ]) ) await state.update_data(new_rules=new_rules) @admin_required @error_handler async def save_rules( callback: types.CallbackQuery, db_user: User, state: FSMContext, db: AsyncSession ): data = await state.get_data() new_rules = data.get('new_rules') if not new_rules: await callback.answer("❌ Ошибка: текст правил не найден", show_alert=True) return is_valid, error_msg = validate_html_tags(new_rules) if not is_valid: await callback.message.edit_text( f"❌ Ошибка при сохранении:\n{error_msg}\n\n" f"Правила не были сохранены из-за ошибок в HTML разметке.", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="🔄 Попробовать снова", callback_data="admin_edit_rules")], [types.InlineKeyboardButton(text="📋 К правилам", callback_data="admin_rules")] ]) ) await state.clear() await callback.answer() return try: await create_or_update_rules( db=db, content=new_rules, language=db_user.language ) from app.localization.texts import clear_rules_cache clear_rules_cache() from app.localization.texts import refresh_rules_cache await refresh_rules_cache(db_user.language) await callback.message.edit_text( "✅ Правила сервиса успешно обновлены!\n\n" "✓ Новые правила сохранены в базе данных\n" "✓ HTML теги проверены и корректны\n" "✓ Кеш правил очищен и обновлен\n" "✓ Правила будут показываться пользователям\n\n" f"📊 Размер текста: {len(new_rules)} символов", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="👀 Просмотреть", callback_data="admin_view_rules")], [types.InlineKeyboardButton(text="📋 К правилам", callback_data="admin_rules")] ]) ) await state.clear() logger.info(f"Правила сервиса обновлены администратором {db_user.telegram_id}") await callback.answer() except Exception as e: logger.error(f"Ошибка сохранения правил: {e}") await callback.message.edit_text( "❌ Ошибка при сохранении правил\n\n" "Произошла ошибка при записи в базу данных. Попробуйте еще раз.", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="🔄 Попробовать снова", callback_data="admin_save_rules")], [types.InlineKeyboardButton(text="📋 К правилам", callback_data="admin_rules")] ]) ) await callback.answer() @admin_required @error_handler async def clear_rules_confirmation( callback: types.CallbackQuery, db_user: User, db: AsyncSession ): await callback.message.edit_text( "🗑️ Очистка правил сервиса\n\n" "⚠️ ВНИМАНИЕ! Вы собираетесь полностью удалить все правила сервиса.\n\n" "После очистки пользователи будут видеть стандартные правила по умолчанию.\n\n" "Это действие нельзя отменить. Продолжить?", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [ types.InlineKeyboardButton(text="✅ Да, очистить", callback_data="admin_confirm_clear_rules"), types.InlineKeyboardButton(text="❌ Отмена", callback_data="admin_rules") ] ]) ) await callback.answer() @admin_required @error_handler async def confirm_clear_rules( callback: types.CallbackQuery, db_user: User, db: AsyncSession ): try: await clear_all_rules(db, db_user.language) from app.localization.texts import clear_rules_cache clear_rules_cache() await callback.message.edit_text( "✅ Правила успешно очищены!\n\n" "✓ Все пользовательские правила удалены\n" "✓ Теперь используются стандартные правила\n" "✓ Кеш правил очищен\n\n" "Пользователи будут видеть правила по умолчанию.", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="📝 Создать новые", callback_data="admin_edit_rules")], [types.InlineKeyboardButton(text="👀 Посмотреть текущие", callback_data="admin_view_rules")], [types.InlineKeyboardButton(text="📋 К правилам", callback_data="admin_rules")] ]) ) logger.info(f"Правила очищены администратором {db_user.telegram_id}") await callback.answer() except Exception as e: logger.error(f"Ошибка при очистке правил: {e}") await callback.answer("❌ Ошибка при очистке правил", show_alert=True) @admin_required @error_handler async def show_html_help( callback: types.CallbackQuery, db_user: User, db: AsyncSession ): help_text = get_html_help_text() await callback.message.edit_text( f"ℹ️ Справка по HTML форматированию\n\n{help_text}", reply_markup=types.InlineKeyboardMarkup(inline_keyboard=[ [types.InlineKeyboardButton(text="📝 Редактировать правила", callback_data="admin_edit_rules")], [types.InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_rules")] ]) ) await callback.answer() def register_handlers(dp: Dispatcher): dp.callback_query.register(show_rules_management, F.data == "admin_rules") dp.callback_query.register(view_current_rules, F.data == "admin_view_rules") dp.callback_query.register(start_edit_rules, F.data == "admin_edit_rules") dp.callback_query.register(save_rules, F.data == "admin_save_rules") dp.callback_query.register(clear_rules_confirmation, F.data == "admin_clear_rules") dp.callback_query.register(confirm_clear_rules, F.data == "admin_confirm_clear_rules") dp.callback_query.register(show_html_help, F.data == "admin_rules_help") dp.message.register(process_rules_edit, AdminStates.editing_rules_page)