diff --git a/src/fabledassistant/services/events.py b/src/fabledassistant/services/events.py index c1679c1..381e655 100644 --- a/src/fabledassistant/services/events.py +++ b/src/fabledassistant/services/events.py @@ -7,7 +7,7 @@ import uuid from datetime import datetime, timedelta, timezone from dateutil.rrule import rrulestr -from sqlalchemy import or_, select +from sqlalchemy import and_, or_, select from fabledassistant.models import async_session from fabledassistant.models.event import Event @@ -85,19 +85,30 @@ async def list_events( dicts (same shape as Event.to_dict()). """ async with async_session() as session: + # Match strategy: + # - Recurring events: fetch all, expand via rrule below. + # - Non-recurring with an end_dt: standard overlap — starts before + # date_to and ends after date_from. + # - Non-recurring with no end_dt: treat as a point event at + # start_dt, include only if start_dt falls within the window. + # (Previously this branch matched any event with a null end_dt, + # returning all past events as "happening today".) result = await session.execute( select(Event).where( Event.user_id == user_id, - # Base window: non-recurring events must overlap range; - # recurring events always need to be fetched so they can be expanded. or_( Event.recurrence.isnot(None), - Event.start_dt <= date_to, - ), - or_( - Event.end_dt.is_(None), - Event.end_dt >= date_from, - Event.recurrence.isnot(None), + and_( + Event.recurrence.is_(None), + Event.start_dt <= date_to, + or_( + Event.end_dt >= date_from, + and_( + Event.end_dt.is_(None), + Event.start_dt >= date_from, + ), + ), + ), ), ).order_by(Event.start_dt) )