From cc220b8a4f36eff06a3222f8bf82744070ff6789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Ja=C5=A1ek?= Date: Tue, 16 Jul 2024 09:20:58 +0200 Subject: [PATCH] fix date filtering (#2024) * fix date filtering - always return ongoing events for selected date - check properly all_day / no_end_time flags SDESK-7334 * fix query for all day events there is no end time for all day events as well * add test --- server/features/search_events.feature | 50 +++++++++++++++ server/planning/search/queries/elastic.py | 74 ++++++++++++++++----- server/planning/search/queries/events.py | 78 ++++------------------- 3 files changed, 118 insertions(+), 84 deletions(-) diff --git a/server/features/search_events.feature b/server/features/search_events.feature index 71d98519d..000d7ebe8 100644 --- a/server/features/search_events.feature +++ b/server/features/search_events.feature @@ -326,3 +326,53 @@ Feature: Event Search ]} """ + @auth + Scenario: Filter by date using America/Toronto timezone + Given "events" + """ + [{ + "guid": "all_day_multi", + "name": "all day event multiday", + "dates": {"start": "2024-07-14T00:00:00+0000", "end": "2024-07-16T00:00:00+0000", "all_day": true} + }, { + "guid": "all_day_single", + "name": "all day single day", + "dates": {"start": "2024-07-15T00:00:00+0000", "end": "2024-07-15T00:00:00+0000", "all_day": true} + }, { + "guid": "no_end_time_multi", + "name": "no end time multiday", + "dates": {"start": "2024-07-13T10:00:00+0000", "end": "2024-07-15T00:00:00+0000", "no_end_time": true} + }, { + "guid": "no_end_time_single", + "name": "no end time single day", + "dates": {"start": "2024-07-15T10:00:00+0000", "end": "2024-07-15T10:00:00+0000", "no_end_time": true} + }, { + "guid": "matching", + "name": "regular", + "dates": {"start": "2024-07-15T10:00:00+0000", "end": "2024-07-16T00:00:00+0000"} + }, + { + "guid": "not matching", + "name": "not matching", + "dates": {"start": "2024-07-01T10:00:00+0000", "end": "2024-07-02T00:00:00+0000"} + } + ] + """ + When we get "/events_planning_search?repo=events&only_future=false&time_zone=America/Toronto&start_date=2024-07-15T04:00:00" + Then we get list with 5 items + """ + {"_items": [ + {"guid": "all_day_multi"}, + {"guid": "all_day_single"}, + {"guid": "no_end_time_multi"}, + {"guid": "no_end_time_single"}, + {"guid": "matching"} + ]} + """ + When we get "/events_planning_search?repo=events&only_future=false&time_zone=America/Toronto&start_date=2024-07-16T04:00:00" + Then we get list with 1 items + """ + {"_items": [ + {"guid": "all_day_multi"} + ]} + """ diff --git a/server/planning/search/queries/elastic.py b/server/planning/search/queries/elastic.py index 523b19a3c..025b5a4e9 100644 --- a/server/planning/search/queries/elastic.py +++ b/server/planning/search/queries/elastic.py @@ -209,26 +209,66 @@ def field_range(query: ElasticRangeParams): local_params = params.copy() local_params.pop("time_zone", None) for key in ("gt", "gte", "lt", "lte"): - if local_params.get(key) and "T" in local_params[key] and query.time_zone: - tz = pytz.timezone(query.time_zone) + if local_params.get(key) and "T" in local_params[key] and params.get("time_zone"): + tz = pytz.timezone(params["time_zone"]) utc_value = datetime.fromisoformat(local_params[key].replace("+0000", "+00:00")) local_value = utc_value.astimezone(tz) local_params[key] = local_value.strftime("%Y-%m-%d") - return { - "bool": { - "should": [ - {"range": {query.field: params}}, - { - "bool": { - "must": [ - {"term": {"dates.all_day": True}}, - {"range": {query.field: local_params}}, - ], - } - }, - ], - }, - } + if query.field == "dates.start": + return { + "bool": { + "should": [ + { + "bool": { + "must_not": [ + {"term": {"dates.all_day": True}}, + ], + "must": [ + {"range": {query.field: params}}, + ], + }, + }, + { + "bool": { + "must": [ + {"term": {"dates.all_day": True}}, + {"range": {query.field: local_params}}, + ], + }, + }, + ], + }, + } + else: + return { + "bool": { + "should": [ + { + "bool": { + "must_not": [ + {"term": {"dates.all_day": True}}, + {"term": {"dates.no_end_time": True}}, + ], + "must": [ + {"range": {query.field: params}}, + ], + }, + }, + { + "bool": { + "should": [ + {"term": {"dates.all_day": True}}, + {"term": {"dates.no_end_time": True}}, + ], + "must": [ + {"range": {query.field: local_params}}, + ], + "minimum_should_match": 1, + }, + }, + ], + }, + } return {"range": {query.field: params}} diff --git a/server/planning/search/queries/events.py b/server/planning/search/queries/events.py index 5502a4d1b..1ed8785ef 100644 --- a/server/planning/search/queries/events.py +++ b/server/planning/search/queries/events.py @@ -255,16 +255,7 @@ def search_date_start(params: Dict[str, Any], query: elastic.ElasticQuery): if not date_filter and start_date and not end_date: query.filter.append( - elastic.bool_or( - [ - elastic.date_range( - elastic.ElasticRangeParams(field="dates.start", gte=start_date, time_zone=time_zone) - ), - elastic.date_range( - elastic.ElasticRangeParams(field="dates.end", gte=start_date, time_zone=time_zone) - ), - ] - ) + elastic.date_range(elastic.ElasticRangeParams(field="dates.end", gte=start_date, time_zone=time_zone)), ) @@ -273,16 +264,7 @@ def search_date_end(params: Dict[str, Any], query: elastic.ElasticQuery): if not date_filter and not start_date and end_date: query.filter.append( - elastic.bool_or( - [ - elastic.date_range( - elastic.ElasticRangeParams(field="dates.start", lte=end_date, time_zone=time_zone) - ), - elastic.date_range( - elastic.ElasticRangeParams(field="dates.end", lte=end_date, time_zone=time_zone) - ), - ] - ) + elastic.date_range(elastic.ElasticRangeParams(field="dates.start", lte=end_date, time_zone=time_zone)), ) @@ -291,55 +273,17 @@ def search_date_range(params: Dict[str, Any], query: elastic.ElasticQuery): if not date_filter and start_date and end_date: query.filter.append( - elastic.bool_or( + elastic.bool_and( [ - elastic.bool_and( - [ - elastic.date_range( - elastic.ElasticRangeParams( - field="dates.start", - gte=start_date, - time_zone=time_zone, - ) - ), - elastic.date_range( - elastic.ElasticRangeParams(field="dates.end", lte=end_date, time_zone=time_zone) - ), - ] - ), - elastic.bool_and( - [ - elastic.date_range( - elastic.ElasticRangeParams( - field="dates.start", - lt=start_date, - time_zone=time_zone, - ) - ), - elastic.date_range( - elastic.ElasticRangeParams(field="dates.end", gt=end_date, time_zone=time_zone) - ), - ] + elastic.date_range( + elastic.ElasticRangeParams( + field="dates.start", + gte=end_date, + time_zone=time_zone, + ), ), - elastic.bool_or( - [ - elastic.date_range( - elastic.ElasticRangeParams( - field="dates.start", - gte=start_date, - lte=end_date, - time_zone=time_zone, - ) - ), - elastic.date_range( - elastic.ElasticRangeParams( - field="dates.end", - gte=start_date, - lte=end_date, - time_zone=time_zone, - ) - ), - ] + elastic.date_range( + elastic.ElasticRangeParams(field="dates.end", lte=start_date, time_zone=time_zone) ), ] )