"""
Пользовательские команды
Доступны всем жильцам
"""
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)