✅ Регистрация и верификация жильцов ✅ Рейтинг активности (уровни) ✅ Детект шпионов (Score 0-100) ✅ Анти-мат система (3 предупреждения → бан) ✅ Админ-панель с рассылкой ✅ Учёт квартир (несколько жильцов) ✅ Телефоны экстренных служб и мастеров ✅ Еженедельный экспорт JSON ✅ Прокси (socks5) для обхода РКН Бекап: backups/versions/v1.0_mvp_2026-02-26/ Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
166 lines
5.4 KiB
Python
166 lines
5.4 KiB
Python
"""
|
||
Thanks Service — система благодарностей пользователей
|
||
"""
|
||
import logging
|
||
from datetime import datetime
|
||
from typing import Dict, List, Optional
|
||
from sqlalchemy import select, func
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class ThanksService:
|
||
"""Сервис благодарностей"""
|
||
|
||
def __init__(self, session: AsyncSession):
|
||
self.session = session
|
||
|
||
async def give_thank(self, from_user_id: int, to_user_id: int, message: str = None) -> bool:
|
||
"""
|
||
Отправить благодарность
|
||
Returns: True если успешно
|
||
"""
|
||
from database.models import Thank
|
||
|
||
# Нельзя поблагодарить самого себя
|
||
if from_user_id == to_user_id:
|
||
return False
|
||
|
||
# Создаём благодарность
|
||
thank = Thank(
|
||
from_user_id=from_user_id,
|
||
to_user_id=to_user_id,
|
||
message=message
|
||
)
|
||
self.session.add(thank)
|
||
await self.session.commit()
|
||
|
||
logger.info(f"Благодарность от {from_user_id} к {to_user_id}")
|
||
return True
|
||
|
||
async def get_user_thanks(self, user_id: int) -> Dict:
|
||
"""
|
||
Получить статистику благодарностей пользователя
|
||
Returns: dict со статистикой
|
||
"""
|
||
from database.models import Thank
|
||
|
||
# Полученные благодарности
|
||
stmt_received = (
|
||
select(func.count(Thank.id))
|
||
.where(Thank.to_user_id == user_id)
|
||
)
|
||
result = await self.session.execute(stmt_received)
|
||
received_count = result.scalar() or 0
|
||
|
||
# Отправленные благодарности
|
||
stmt_given = (
|
||
select(func.count(Thank.id))
|
||
.where(Thank.from_user_id == user_id)
|
||
)
|
||
result = await self.session.execute(stmt_given)
|
||
given_count = result.scalar() or 0
|
||
|
||
# Последние полученные
|
||
stmt_last = (
|
||
select(Thank)
|
||
.where(Thank.to_user_id == user_id)
|
||
.order_by(Thank.created_at.desc())
|
||
.limit(5)
|
||
)
|
||
result = await self.session.execute(stmt_last)
|
||
last_received = list(result.scalars().all())
|
||
|
||
return {
|
||
'received': received_count,
|
||
'given': given_count,
|
||
'last_received': [
|
||
{
|
||
'from': t.from_user_id,
|
||
'message': t.message,
|
||
'created_at': t.created_at.isoformat()
|
||
}
|
||
for t in last_received
|
||
]
|
||
}
|
||
|
||
async def get_leaderboard(self, limit: int = 10) -> List[Dict]:
|
||
"""
|
||
Получить топ пользователей по благодарностям
|
||
Returns: список пользователей с количеством благодарностей
|
||
"""
|
||
from database.models import Thank, User
|
||
|
||
stmt = (
|
||
select(
|
||
User.user_id,
|
||
User.full_name,
|
||
User.apartment,
|
||
func.count(Thank.id).label('thanks_count')
|
||
)
|
||
.join(Thank, User.user_id == Thank.to_user_id, isouter=True)
|
||
.group_by(User.user_id)
|
||
.order_by(func.count(Thank.id).desc())
|
||
.limit(limit)
|
||
)
|
||
result = await self.session.execute(stmt)
|
||
rows = list(result.all())
|
||
|
||
return [
|
||
{
|
||
'user_id': row.user_id,
|
||
'name': row.full_name or f'user{row.user_id}',
|
||
'apartment': row.apartment or '?',
|
||
'thanks': row.thanks_count
|
||
}
|
||
for row in rows
|
||
]
|
||
|
||
async def get_thanks_history(self, user_id: int, limit: int = 20) -> List[Dict]:
|
||
"""
|
||
Получить историю благодарностей пользователя
|
||
Returns: список благодарностей
|
||
"""
|
||
from database.models import Thank
|
||
|
||
stmt = (
|
||
select(Thank)
|
||
.where((Thank.from_user_id == user_id) | (Thank.to_user_id == user_id))
|
||
.order_by(Thank.created_at.desc())
|
||
.limit(limit)
|
||
)
|
||
result = await self.session.execute(stmt)
|
||
thanks = list(result.scalars().all())
|
||
|
||
return [
|
||
{
|
||
'from': t.from_user_id,
|
||
'to': t.to_user_id,
|
||
'message': t.message,
|
||
'created_at': t.created_at.isoformat(),
|
||
'is_received': t.to_user_id == user_id
|
||
}
|
||
for t in thanks
|
||
]
|
||
|
||
async def has_thanked_today(self, from_user_id: int, to_user_id: int) -> bool:
|
||
"""
|
||
Проверить, благодарил ли уже пользователь сегодня
|
||
Returns: True если уже благодарил
|
||
"""
|
||
from database.models import Thank
|
||
from datetime import timedelta
|
||
|
||
today = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
|
||
|
||
stmt = (
|
||
select(func.count(Thank.id))
|
||
.where(Thank.from_user_id == from_user_id)
|
||
.where(Thank.to_user_id == to_user_id)
|
||
.where(Thank.created_at >= today)
|
||
)
|
||
result = await self.session.execute(stmt)
|
||
count = result.scalar() or 0
|
||
|
||
return count > 0
|