""" Events Service — календарь событий дома """ import logging from datetime import datetime, timedelta from typing import Dict, List, Optional from sqlalchemy import select, func, delete from sqlalchemy.ext.asyncio import AsyncSession logger = logging.getLogger(__name__) class EventsService: """Сервис событий""" def __init__(self, session: AsyncSession): self.session = session async def create_event( self, title: str, event_date: datetime, description: str = None, event_type: str = 'general', location: str = None, created_by: int = None ) -> int: """ Создать событие Returns: ID события """ from database.models import Event event = Event( title=title, description=description, event_type=event_type, event_date=event_date, location=location, created_by=created_by ) self.session.add(event) await self.session.commit() await self.session.refresh(event) logger.info(f"Событие {title} создано (ID: {event.id})") return event.id async def join_event(self, event_id: int, user_id: int) -> bool: """ Присоединиться к событию Returns: True если успешно """ from database.models import EventParticipant # Проверяем не участвует ли уже stmt = select(EventParticipant).where( EventParticipant.event_id == event_id, EventParticipant.user_id == user_id ) result = await self.session.execute(stmt) if result.scalar_one_or_none(): return False participant = EventParticipant( event_id=event_id, user_id=user_id ) self.session.add(participant) await self.session.commit() logger.info(f"Пользователь {user_id} присоединился к событию {event_id}") return True async def leave_event(self, event_id: int, user_id: int) -> bool: """ Отписаться от события Returns: True если успешно """ from database.models import EventParticipant stmt = delete(EventParticipant).where( EventParticipant.event_id == event_id, EventParticipant.user_id == user_id ) await self.session.execute(stmt) await self.session.commit() logger.info(f"Пользователь {user_id} отписался от события {event_id}") return True async def get_event(self, event_id: int) -> Optional[Dict]: """Получить информацию о событии""" from database.models import Event event = await self.session.get(Event, event_id) if not event: return None # Считаем участников stmt = select(func.count()).select_from(EventParticipant).where( EventParticipant.event_id == event_id ) result = await self.session.execute(stmt) participants_count = result.scalar() or 0 return { 'id': event.id, 'title': event.title, 'description': event.description, 'event_type': event.event_type, 'event_date': event.event_date, 'location': event.location, 'created_by': event.created_by, 'participants_count': participants_count, 'is_active': event.is_active } async def get_upcoming_events(self, limit: int = 10) -> List[Dict]: """Получить предстоящие события""" from database.models import Event stmt = ( select(Event) .where(Event.is_active == True) .where(Event.event_date >= datetime.utcnow()) .order_by(Event.event_date) .limit(limit) ) result = await self.session.execute(stmt) events = list(result.scalars().all()) return [ { 'id': e.id, 'title': e.title, 'event_date': e.event_date, 'location': e.location, 'event_type': e.event_type } for e in events ] async def get_user_events(self, user_id: int) -> List[Dict]: """Получить события пользователя""" from database.models import Event, EventParticipant stmt = ( select(Event) .join(EventParticipant, Event.id == EventParticipant.event_id) .where(EventParticipant.user_id == user_id) .where(Event.is_active == True) .order_by(Event.event_date) ) result = await self.session.execute(stmt) events = list(result.scalars().all()) return [ { 'id': e.id, 'title': e.title, 'event_date': e.event_date, 'location': e.location, 'event_type': e.event_type } for e in events ] async def cancel_event(self, event_id: int) -> bool: """Отменить событие""" from database.models import Event event = await self.session.get(Event, event_id) if not event: return False event.is_active = False await self.session.commit() logger.info(f"Событие {event_id} отменено") return True async def get_participants(self, event_id: int) -> List[Dict]: """Получить участников события""" from database.models import EventParticipant, User stmt = ( select(User) .join(EventParticipant, User.user_id == EventParticipant.user_id) .where(EventParticipant.event_id == event_id) ) result = await self.session.execute(stmt) users = list(result.scalars().all()) return [ { 'user_id': u.user_id, 'name': u.full_name or u.username or f'user{u.user_id}', 'apartment': u.apartment } for u in users ] async def get_events_for_reminder(self, hours_ahead: int = 24) -> List[Dict]: """Получить события для напоминания""" from database.models import Event now = datetime.utcnow() future = now + timedelta(hours=hours_ahead) stmt = ( select(Event) .where(Event.is_active == True) .where(Event.reminder_sent == False) .where(Event.event_date > now) .where(Event.event_date <= future) ) result = await self.session.execute(stmt) events = list(result.scalars().all()) return [ { 'id': e.id, 'title': e.title, 'event_date': e.event_date, 'location': e.location, 'description': e.description } for e in events ] async def mark_reminder_sent(self, event_id: int): """Отметить что напоминание отправлено""" from database.models import Event event = await self.session.get(Event, event_id) if event: event.reminder_sent = True await self.session.commit() def get_event_type_emoji(self, event_type: str) -> str: """Получить emoji типа события""" emojis = { 'meeting': '📋', 'subbotnik': '🧹', 'holiday': '🎉', 'sport': '⚽', 'kids': '🎈', 'general': '📅' } return emojis.get(event_type, '📅')