✅ Регистрация и верификация жильцов ✅ Рейтинг активности (уровни) ✅ Детект шпионов (Score 0-100) ✅ Анти-мат система (3 предупреждения → бан) ✅ Админ-панель с рассылкой ✅ Учёт квартир (несколько жильцов) ✅ Телефоны экстренных служб и мастеров ✅ Еженедельный экспорт JSON ✅ Прокси (socks5) для обхода РКН Бекап: backups/versions/v1.0_mvp_2026-02-26/ Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
249 lines
10 KiB
Python
249 lines
10 KiB
Python
"""
|
||
Thanks — система благодарностей пользователей
|
||
"""
|
||
import logging
|
||
from aiogram import Router, F
|
||
from aiogram.types import Message
|
||
from aiogram.filters import Command, StateFilter
|
||
from aiogram.fsm.state import State, StatesGroup
|
||
from aiogram.fsm.context import FSMContext
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
from sqlalchemy import select
|
||
from database.db import AsyncSessionLocal
|
||
from database.models import User
|
||
from services.thanks import ThanksService
|
||
from services.achievements import AchievementsService
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
router = Router()
|
||
|
||
|
||
# =============================================================================
|
||
# FSM для отправки благодарности
|
||
# =============================================================================
|
||
|
||
class ThankState(StatesGroup):
|
||
waiting_for_user = State()
|
||
waiting_for_message = State()
|
||
|
||
|
||
# =============================================================================
|
||
# ОТПРАВКА БЛАГОДАРНОСТИ
|
||
# =============================================================================
|
||
|
||
@router.message(Command('thank'))
|
||
@router.message(Command('спасибо'))
|
||
async def cmd_thank(message: Message, state: FSMContext):
|
||
"""
|
||
Поблагодарить пользователя
|
||
Использование: /thank @username или /thank <user_id>
|
||
"""
|
||
args = message.text.split(maxsplit=1)
|
||
|
||
if len(args) < 2:
|
||
await message.answer(
|
||
'🙏 <b>Отправить благодарность</b>\n\n'
|
||
'Использование:\n'
|
||
'<code>/thank @username</code>\n'
|
||
'или\n'
|
||
'<code>/thank <user_id></code>\n\n'
|
||
'Или ответьте на сообщение командой /thank',
|
||
parse_mode='HTML'
|
||
)
|
||
return
|
||
|
||
# Получаем пользователя
|
||
target_username = args[1].replace('@', '')
|
||
|
||
async with AsyncSessionLocal() as session:
|
||
# Ищем по username
|
||
stmt = select(User).where(User.username == target_username)
|
||
result = await session.execute(stmt)
|
||
target_user = result.scalar_one_or_none()
|
||
|
||
if not target_user:
|
||
# Пробуем по ID
|
||
try:
|
||
target_id = int(target_username)
|
||
target_user = await session.get(User, target_id)
|
||
except ValueError:
|
||
pass
|
||
|
||
if not target_user:
|
||
await message.answer(f'❌ Пользователь @{target_username} не найден')
|
||
return
|
||
|
||
# Проверяем что не сам себе
|
||
if target_user.user_id == message.from_user.id:
|
||
await message.answer('❌ Нельзя поблагодарить самого себя!')
|
||
return
|
||
|
||
# Проверяем не благодарил ли уже сегодня
|
||
thanks_service = ThanksService(session)
|
||
if await thanks_service.has_thanked_today(message.from_user.id, target_user.user_id):
|
||
await message.answer(
|
||
'⚠️ Вы уже благодарили этого пользователя сегодня!\n'
|
||
'Можно поблагодарить только один раз в день.'
|
||
)
|
||
return
|
||
|
||
# Сохраняем данные для следующего шага
|
||
await state.update_data(target_user_id=target_user.user_id)
|
||
await state.update_data(target_name=target_user.full_name or f'@{target_user.username}')
|
||
|
||
await message.answer(
|
||
f'🙏 <b>Благодарность для {target_user.full_name or f"@{target_user.username}"}</b>\n\n'
|
||
'Отправьте текст благодарности (необязательно) или "пропустить":',
|
||
parse_mode='HTML'
|
||
)
|
||
await state.set_state(ThankState.waiting_for_message)
|
||
|
||
|
||
@router.message(ThankState.waiting_for_message)
|
||
async def process_thank_message(message: Message, state: FSMContext):
|
||
"""Получили текст благодарности"""
|
||
data = await state.get_data()
|
||
target_user_id = data.get('target_user_id')
|
||
target_name = data.get('target_name')
|
||
|
||
thank_message = message.text if message.text.lower() != 'пропустить' else None
|
||
|
||
async with AsyncSessionLocal() as session:
|
||
thanks_service = ThanksService(session)
|
||
success = await thanks_service.give_thank(
|
||
message.from_user.id,
|
||
target_user_id,
|
||
thank_message
|
||
)
|
||
|
||
if success:
|
||
# Уведомляем отправителя
|
||
await message.answer(
|
||
f'✅ <b>Благодарность отправлена!</b>\n\n'
|
||
f'Получатель: {target_name}\n'
|
||
f'{"Сообщение: " + thank_message if thank_message else ""}',
|
||
parse_mode='HTML'
|
||
)
|
||
|
||
# Уведомляем получателя
|
||
try:
|
||
await message.bot.send_message(
|
||
target_user_id,
|
||
f'🙏 <b>Вам благодарность!</b>\n\n'
|
||
f'От: {message.from_user.full_name}\n'
|
||
f'{"Сообщение: " + thank_message if thank_message else "Спасибо за помощь!"}\n\n'
|
||
f'+10 к рейтингу!',
|
||
parse_mode='HTML'
|
||
)
|
||
except Exception as e:
|
||
logger.error(f'Не удалось уведомить о благодарности: {e}')
|
||
|
||
# Обновляем рейтинг получателя (+10)
|
||
target_user = await session.get(User, target_user_id)
|
||
if target_user:
|
||
target_user.rating += 10
|
||
target_user.update_level()
|
||
|
||
# Проверяем достижение "Помощник" (получил благодарность)
|
||
achievements_service = AchievementsService(session)
|
||
awarded = await achievements_service.check_and_award(
|
||
target_user_id,
|
||
helper=True # Флаг для достижения помощника
|
||
)
|
||
|
||
if 'helper' in awarded:
|
||
await message.bot.send_message(
|
||
target_user_id,
|
||
'🏆 <b>Новое достижение!</b>\n\n'
|
||
'🤝 <b>Помощник</b>\n\n'
|
||
'Получил благодарность от соседа\n\n'
|
||
'Продолжайте помогать!',
|
||
parse_mode='HTML'
|
||
)
|
||
|
||
await session.commit()
|
||
|
||
await state.clear()
|
||
|
||
|
||
# =============================================================================
|
||
# МОИ БЛАГОДАРНОСТИ
|
||
# =============================================================================
|
||
|
||
@router.message(Command('my_thanks'))
|
||
@router.message(Command('мои_спасибо'))
|
||
async def cmd_my_thanks(message: Message):
|
||
"""Показать свои благодарности"""
|
||
user_id = message.from_user.id
|
||
|
||
async with AsyncSessionLocal() as session:
|
||
thanks_service = ThanksService(session)
|
||
stats = await thanks_service.get_user_thanks(user_id)
|
||
|
||
text = '🙏 <b>Ваши благодарности</b>\n\n'
|
||
text += f'✅ Получено: {stats["received"]}\n'
|
||
text += f'📤 Отправлено: {stats["given"]}\n'
|
||
|
||
if stats['last_received']:
|
||
text += '\n<b>Последние полученные:</b>\n'
|
||
for thank in stats['last_received'][:3]:
|
||
text += f' • От user{thank["from"]}: {thank["message"] or "Спасибо!"}\n'
|
||
|
||
await message.answer(text, parse_mode='HTML')
|
||
|
||
|
||
# =============================================================================
|
||
# ТОП ПО БЛАГОДАРНОСТЯМ
|
||
# =============================================================================
|
||
|
||
@router.message(Command('thanks_top'))
|
||
@router.message(Command('топ_спасибо'))
|
||
async def cmd_thanks_top(message: Message):
|
||
"""Топ пользователей по благодарностям"""
|
||
async with AsyncSessionLocal() as session:
|
||
thanks_service = ThanksService(session)
|
||
leaderboard = await thanks_service.get_leaderboard(10)
|
||
|
||
if not leaderboard:
|
||
await message.answer('ℹ️ Пока нет благодарностей')
|
||
return
|
||
|
||
text = '🙏 <b>Топ по благодарностям</b>\n\n'
|
||
|
||
medals = ['🥇', '🥈', '🥉']
|
||
|
||
for i, user in enumerate(leaderboard):
|
||
medal = medals[i] if i < 3 else f'{i+1}.'
|
||
text += f'{medal} {user["name"]} (кв. {user["apartment"]}) — {user["thanks"]} благодар.\n'
|
||
|
||
await message.answer(text, parse_mode='HTML')
|
||
|
||
|
||
# =============================================================================
|
||
# ИСТОРИЯ БЛАГОДАРНОСТЕЙ
|
||
# =============================================================================
|
||
|
||
@router.message(Command('thanks_history'))
|
||
@router.message(Command('история_спасибо'))
|
||
async def cmd_thanks_history(message: Message):
|
||
"""История благодарностей пользователя"""
|
||
user_id = message.from_user.id
|
||
|
||
async with AsyncSessionLocal() as session:
|
||
thanks_service = ThanksService(session)
|
||
history = await thanks_service.get_thanks_history(user_id)
|
||
|
||
if not history:
|
||
await message.answer('ℹ️ История благодарностей пуста')
|
||
return
|
||
|
||
text = '🙏 <b>История благодарностей</b>\n\n'
|
||
|
||
for thank in history[:10]:
|
||
if thank['is_received']:
|
||
text += f'✅ Получено от user{thank["from"]}: {thank["message"] or "Спасибо!"}\n'
|
||
else:
|
||
text += f'📤 Отправлено user{thank["to"]}: {thank["message"] or "Спасибо!"}\n'
|
||
|
||
await message.answer(text, parse_mode='HTML')
|