""" Пользовательские команды Доступны всем жильцам """ import logging import json from aiogram import Router, F from aiogram.types import Message, CallbackQuery from aiogram.filters import Command, CommandStart from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from database.db import AsyncSessionLocal from database.models import User, Service, Announcement from keyboards.inline import get_main_menu, get_phones_menu from utils.formatters import format_phone_list import config logger = logging.getLogger(__name__) router = Router() @router.message(CommandStart()) async def cmd_start(message: Message): """Команда /start""" user_id = message.from_user.id async with AsyncSessionLocal() as session: # Проверяем, есть ли пользователь в БД stmt = select(User).where(User.user_id == user_id) result = await session.execute(stmt) user = result.scalar_one_or_none() if not user: # Создаём нового пользователя user = User( user_id=user_id, username=message.from_user.username, first_name=message.from_user.first_name, last_name=message.from_user.last_name, ) session.add(user) await session.commit() welcome_text = ( f'🏠 Добро пожаловать, {message.from_user.first_name}!\n\n' f'Я — домовой бот нашего дома.\n\n' f'❗ Важно: Для полного доступа пройдите верификацию.\n' f'Отправьте мне номер вашей квартиры (например: 45 или 12А)' ) await message.answer(welcome_text, parse_mode='HTML') else: # Обновляем имя user.username = message.from_user.username user.first_name = message.from_user.first_name user.last_name = message.from_user.last_name await session.commit() if user.verified: await message.answer( f'👋 Здравствуйте, {message.from_user.first_name}!\n\n' f'Вы верифицированы (кв. {user.apartment}).\n' f'Выберите действие:', reply_markup=get_main_menu(), parse_mode='HTML' ) else: await message.answer( f'👋 Здравствуйте, {message.from_user.first_name}!\n\n' f'⏳ Вы ещё не верифицированы.\n' f'Отправьте номер квартиры для верификации.', parse_mode='HTML' ) @router.message(Command('помощь')) @router.message(Command('help')) async def cmd_help(message: Message): """Справка по командам""" text = '''📱 Команды бота: Для всех жильцов: 📞 /телефон — Экстренные службы 👷 /мастера — Сантехники, электрики 👮 /участковый — Контакты полиции 📅 /график — Отключения воды/света 📢 /объявления — Новости дома 🔍 /моя_квартира — Проверка привязки Верификация: Просто отправьте номер квартиры текстом Администратору: /admin — Панель админа /stats — Статистика чата /spies — Подозрительные /export — Экспорт JSON /users — Список жильцов''' await message.answer(text, parse_mode='HTML', reply_markup=get_main_menu()) @router.callback_query(F.data == 'help') async def cb_help(callback: CallbackQuery): """Справка (callback)""" await callback.answer() text = '''🏠 Домовой бот — помощь Этот бот создан для помощи жильцам нашего дома. 📞 Экстренные телефоны Быстрый доступ к телефонам служб 👷 Мастера Проверенные сантехники и электрики 🔍 Моя квартира Проверить привязку к квартире ⏳ Верификация Отправьте номер квартиры текстом''' await callback.message.answer(text, parse_mode='HTML') @router.callback_query(F.data == 'phones') async def cb_phones(callback: CallbackQuery): """Телефоны — главное меню""" await callback.answer() await callback.message.answer( '📞 Выберите категорию:', reply_markup=get_phones_menu() ) @router.callback_query(F.data == 'phones_emergency') async def cb_phones_emergency(callback: CallbackQuery): """Экстренные телефоны""" await callback.answer() async with AsyncSessionLocal() as session: stmt = select(Service).where(Service.category == 'emergency').order_by(Service.name) result = await session.execute(stmt) services = list(result.scalars().all()) text = '🚨 Экстренные службы\n\n' text += format_phone_list([ { 'name': s.name, 'phone': s.phone, 'description': s.description, 'category': s.category } for s in services ]) if not services: text += 'Список пуст. Администратор, добавьте телефоны в БД.' await callback.message.answer(text, parse_mode='HTML') @router.callback_query(F.data == 'phones_utility') async def cb_phones_utility(callback: CallbackQuery): """ЖКХ службы""" await callback.answer() async with AsyncSessionLocal() as session: stmt = select(Service).where(Service.category == 'utility').order_by(Service.name) result = await session.execute(stmt) services = list(result.scalars().all()) text = '🔧 Службы ЖКХ\n\n' text += format_phone_list([ { 'name': s.name, 'phone': s.phone, 'description': s.description, 'category': s.category } for s in services ]) await callback.message.answer(text, parse_mode='HTML') @router.callback_query(F.data == 'phones_police') async def cb_phones_police(callback: CallbackQuery): """Полиция""" await callback.answer() async with AsyncSessionLocal() as session: stmt = select(Service).where(Service.category == 'police').order_by(Service.name) result = await session.execute(stmt) services = list(result.scalars().all()) text = '👮 Полиция\n\n' text += format_phone_list([ { 'name': s.name, 'phone': s.phone, 'description': s.description, 'category': s.category } for s in services ]) await callback.message.answer(text, parse_mode='HTML') @router.callback_query(F.data == 'masters') async def cb_masters(callback: CallbackQuery): """Мастера""" await callback.answer() async with AsyncSessionLocal() as session: stmt = select(Service).where(Service.category.in_(['masters', 'plumber', 'electrician'])).order_by(Service.name) result = await session.execute(stmt) services = list(result.scalars().all()) text = '👷 Проверенные мастера\n\n' text += format_phone_list([ { 'name': s.name, 'phone': s.phone, 'description': s.description, 'category': s.category, 'rating': s.rating } for s in services ]) await callback.message.answer(text, parse_mode='HTML') @router.callback_query(F.data == 'my_apartment') async def cb_my_apartment(callback: CallbackQuery): """Моя квартира""" await callback.answer() async with AsyncSessionLocal() as session: stmt = select(User).where(User.user_id == callback.from_user.id) result = await session.execute(stmt) user = result.scalar_one_or_none() if not user: text = '❌ Вы не зарегистрированы. Нажмите /start' elif not user.apartment: text = f'⏳ Вы не верифицированы.\n\nОтправьте номер квартиры текстом.' else: status = '✅' if user.verified else '⏳' text = ( f'{status} Ваша квартира: {user.apartment}\n\n' f'Статус: {"Верифицирован" if user.verified else "Не верифицирован"}\n' f'Сообщений: {user.message_count}' ) await callback.message.answer(text, parse_mode='HTML') @router.callback_query(F.data == 'schedule') async def cb_schedule(callback: CallbackQuery): """График отключений""" await callback.answer() # TODO: Загрузить реальный график text = '''📅 График отключений ⚠️ Информация обновляется Вода: • Плановое отключение: каждое второе воскресенье месяца, 9:00-17:00 Электричество: • Без плановых отключений Отопление: • Сезон: октябрь — апрель Для актуальной информации обратитесь в УК.''' await callback.message.answer(text, parse_mode='HTML') @router.callback_query(F.data == 'announcements') async def cb_announcements(callback: CallbackQuery): """Объявления""" await callback.answer() async with AsyncSessionLocal() as session: stmt = ( select(Announcement) .where(Announcement.is_active == True) .order_by(Announcement.is_pinned.desc(), Announcement.created_at.desc()) .limit(10) ) result = await session.execute(stmt) announcements = list(result.scalars().all()) if not announcements: await callback.message.answer('📭 Объявлений нет') return text = '📢 Объявления\n\n' for ann in announcements: pin = '📌 ' if ann.is_pinned else '' text += f'{pin}{ann.title}\n{ann.text[:200]}...\n\n' await callback.message.answer(text, parse_mode='HTML') @router.callback_query(F.data == 'main_menu') async def cb_main_menu(callback: CallbackQuery): """Главное меню""" await callback.answer() await callback.message.answer( '🏠 Главное меню', reply_markup=get_main_menu(), parse_mode='HTML' ) # Текстовые команды (алиасы) @router.message(F.text.lower() == 'телефоны') @router.message(F.text.lower() == 'телефон') async def msg_phones_text(message: Message): """Текстовая команда телефоны""" await message.answer( '📞 Выберите категорию:', reply_markup=get_phones_menu() ) @router.message(F.text.lower() == 'мастера') async def msg_masters_text(message: Message): """Текстовая команда мастера""" await message.answer( '👷 Загружаю список мастеров...', reply_markup=get_main_menu() ) # Перенаправляем на callback async with AsyncSessionLocal() as session: stmt = select(Service).where(Service.category.in_(['masters', 'plumber', 'electrician'])) result = await session.execute(stmt) services = list(result.scalars().all()) text = '👷 Проверенные мастера\n\n' text += format_phone_list([ {'name': s.name, 'phone': s.phone, 'description': s.description, 'rating': s.rating} for s in services ]) await message.answer(text, parse_mode='HTML') @router.message(F.text.lower() == 'помощь') async def msg_help_text(message: Message): """Текстовая команда помощь""" await cmd_help(message)