diff --git a/e2e/cypress/e2e/events/event_embedded_coverage.cy.ts b/e2e/cypress/e2e/events/event_embedded_coverage.cy.ts index ac22deac5..d84ff6a11 100644 --- a/e2e/cypress/e2e/events/event_embedded_coverage.cy.ts +++ b/e2e/cypress/e2e/events/event_embedded_coverage.cy.ts @@ -102,7 +102,7 @@ describe('Planning.Events: embedded coverage', () => { .click(); // Test the new Event appears in the list view - list.expectItemCount(1); + list.expectItemCount(2); list.expectItemText(0, 'slugline of the event'); // Test coverage icons in the related Planning item @@ -361,7 +361,7 @@ describe('Planning.Events: embedded coverage', () => { editor.postButton .should('exist') .should('be.enabled'); - list.expectItemCount(1); + list.expectItemCount(2); list.expectItemText(0, 'slugline of the event'); // Make sure the Text coverage was created as well diff --git a/server/features/combined_export.feature b/server/features/combined_export.feature index 58fa80efd..bcd73aeb0 100644 --- a/server/features/combined_export.feature +++ b/server/features/combined_export.feature @@ -129,6 +129,12 @@ Feature: Export combined Planning and Event items with default template And we get text in "body_html" """

Planning

+

Planning 1

+

desc

+

+

Editorial note: Ed. note 1

+

Planned coverage: Text, Photo +

---

Planning 2

desc 2

@@ -173,6 +179,9 @@ Feature: Export combined Planning and Event items with default template

Event: test

Coverages: Text, Photo

---

+

Planning: Planning 1

+

Coverages: Text, Photo

+

---

Planning: Planning 2

Coverages: Text, Photo

---

@@ -208,6 +217,9 @@ Feature: Export combined Planning and Event items with default template

Event: test

Coverages: Text, Photo

---

+

Planning: Planning 1

+

Coverages: Text, Photo

+

---

Planning: Planning 2

Coverages: Text, Photo

---

@@ -248,6 +260,6 @@ Feature: Export combined Planning and Event items with default template """ {"_items": [{ "slugline": "Foo", - "body_html": "

test

Planning 2

" + "body_html": "

test

Planning 1

Planning 2

" }]} """ diff --git a/server/features/search.feature b/server/features/search.feature index d2f21f973..2c33dcc5c 100644 --- a/server/features/search.feature +++ b/server/features/search.feature @@ -157,12 +157,14 @@ Feature: Search Feature ] """ When we get "/events_planning_search?start_date=2016-01-02T00:00:00%2B0000" - Then we get list with 2 items + Then we get list with 4 items """ { "_items": [ {"_id": "planning_123", "type": "planning"}, - {"_id": "event_123", "type": "event"} + {"_id": "event_123", "type": "event"}, + {"_id": "planning_456", "type": "planning"}, + {"_id": "planning_789", "type": "planning"} ] } """ @@ -172,7 +174,7 @@ Feature: Search Feature { "_items": [ {"_id": "planning_123", "type": "planning"}, - {"_id": "event_123", "type": "event"} + {"_id": "planning_456", "type": "planning"} ] } """ @@ -181,7 +183,7 @@ Feature: Search Feature """ { "_items": [ - {"_id": "event_123", "type": "event"} + {"_id": "planning_789", "type": "planning"} ] } """ @@ -315,14 +317,18 @@ Feature: Search Feature ] """ When we get "/events_planning_search?start_date=2016-01-02T00:00:00%2B0000" - Then we get list with 5 items + Then we get list with 9 items """ { "_items": [ {"_id": "event_123", "type": "event"}, + {"_id": "planning_2", "type": "planning"}, {"_id": "planning_1", "type": "planning"}, {"_id": "event_456", "type": "event"}, + {"_id": "planning_3", "type": "planning"}, + {"_id": "planning_4", "type": "planning"}, {"_id": "event_786", "type": "event"}, + {"_id": "planning_5", "type": "planning"}, {"_id": "planning_6", "type": "planning"} ] } @@ -338,35 +344,41 @@ Feature: Search Feature } """ When we get "/events_planning_search?agendas=sports&calendars=sports&start_date=2016-01-02T00:00:00%2B0000" - Then we get list with 3 items + Then we get list with 5 items """ { "_items": [ {"_id": "event_123", "type": "event"}, + {"_id": "planning_2", "type": "planning"}, {"_id": "event_786", "type": "event"}, + {"_id": "planning_5", "type": "planning"}, {"_id": "planning_1", "type": "planning"} ] } """ When we get "/events_planning_search?agendas=sports&calendars=sports,finance&start_date=2016-01-02T00:00:00%2B0000" - Then we get list with 3 items + Then we get list with 5 items """ { "_items": [ {"_id": "event_123", "type": "event"}, + {"_id": "planning_2", "type": "planning"}, {"_id": "event_786", "type": "event"}, + {"_id": "planning_5", "type": "planning"}, {"_id": "planning_1", "type": "planning"} ] } """ When we get "/events_planning_search?agendas=sports,finance&calendars=sports,finance&start_date=2016-01-02T00:00:00%2B0000" - Then we get list with 4 items + Then we get list with 6 items """ { "_items": [ {"_id": "event_123", "type": "event"}, - {"_id": "event_456", "type": "event"}, + {"_id": "planning_2", "type": "planning"}, + {"_id": "planning_3", "type": "planning"}, {"_id": "event_786", "type": "event"}, + {"_id": "planning_5", "type": "planning"}, {"_id": "planning_1", "type": "planning"} ] } @@ -376,7 +388,7 @@ Feature: Search Feature """ { "_items": [ - {"_id": "event_456", "type": "event"}, + {"_id": "planning_4", "type": "planning"}, {"_id": "planning_6", "type": "planning"} ] } @@ -386,8 +398,8 @@ Feature: Search Feature """ { "_items": [ - {"_id": "event_123", "type": "event"}, - {"_id": "event_786", "type": "event"}, + {"_id": "planning_2", "type": "planning"}, + {"_id": "planning_5", "type": "planning"}, {"_id": "planning_1", "type": "planning"} ] } diff --git a/server/features/search_combined.feature b/server/features/search_combined.feature index 69ad0a0c0..73de96be5 100644 --- a/server/features/search_combined.feature +++ b/server/features/search_combined.feature @@ -176,11 +176,12 @@ Feature: Search Events and Planning """ Then we get OK response When we get "/events_planning_search?only_future=false" - Then we get list with 3 items + Then we get list with 4 items """ {"_items": [ {"_id": "user_2_event_1"}, {"_id": "user_2_event_2"}, + {"_id": "user_2_plan_1"}, {"_id": "user_2_plan_2"} ]} """ @@ -190,14 +191,16 @@ Feature: Search Events and Planning """ Then we get OK response When we get "/events_planning_search?only_future=false" - Then we get list with 6 items + Then we get list with 8 items """ {"_items": [ {"_id": "user_1_event_1"}, {"_id": "user_1_event_2"}, {"_id": "user_2_event_1"}, {"_id": "user_2_event_2"}, + {"_id": "user_1_plan_1"}, {"_id": "user_1_plan_2"}, + {"_id": "user_2_plan_1"}, {"_id": "user_2_plan_2"} ]} """ diff --git a/server/features/search_combined_locks.feature b/server/features/search_combined_locks.feature index fcd9da5c0..b16dcde25 100644 --- a/server/features/search_combined_locks.feature +++ b/server/features/search_combined_locks.feature @@ -97,7 +97,7 @@ Feature: Search Events and Planning Locks When we get "/events_planning_search?only_future=false&lock_state=locked" Then we get list with 0 items When we get "/events_planning_search?only_future=false&lock_state=unlocked" - Then we get list with 7 items + Then we get list with 10 items """ {"_items": [ {"slugline": "e-unlocked", "type": "event"}, @@ -106,7 +106,10 @@ Feature: Search Events and Planning Locks {"slugline": "p-locked", "type": "planning"}, {"slugline": "ep-unlocked", "type": "event"}, {"slugline": "ep-e-locked", "type": "event"}, - {"slugline": "ep-p-locked", "type": "event"} + {"slugline": "ep-p-locked", "type": "event"}, + {"slugline": "ep-unlocked", "type": "planning"}, + {"slugline": "ep-e-locked", "type": "planning"}, + {"slugline": "ep-p-locked", "type": "planning"} ]} """ When we post to "/events/event_2/lock" with success @@ -126,22 +129,25 @@ Feature: Search Events and Planning Locks {"lock_action": "edit"} """ When we get "/events_planning_search?only_future=false&lock_state=locked" - Then we get list with 4 items + Then we get list with 6 items """ {"_items": [ {"slugline": "e-locked", "type": "event"}, {"slugline": "p-locked", "type": "planning"}, {"slugline": "ep-e-locked", "type": "event"}, - {"slugline": "ep-p-locked", "type": "event"} + {"slugline": "ep-p-locked", "type": "event"}, + {"slugline": "ep-e-locked", "type": "planning"}, + {"slugline": "ep-p-locked", "type": "planning"} ]} """ When we get "/events_planning_search?only_future=false&lock_state=unlocked" - Then we get list with 3 items + Then we get list with 4 items """ {"_items": [ {"slugline": "e-unlocked", "type": "event"}, {"slugline": "p-unlocked", "type": "planning"}, - {"slugline": "ep-unlocked", "type": "event"} + {"slugline": "ep-unlocked", "type": "event"}, + {"slugline": "ep-unlocked", "type": "planning"} ]} """ When we post to "/events/event_1/lock" with success @@ -157,7 +163,7 @@ Feature: Search Events and Planning Locks {"lock_action": "edit"} """ When we get "/events_planning_search?only_future=false&lock_state=locked" - Then we get list with 7 items + Then we get list with 10 items """ {"_items": [ {"slugline": "e-unlocked", "type": "event"}, @@ -166,7 +172,10 @@ Feature: Search Events and Planning Locks {"slugline": "p-locked", "type": "planning"}, {"slugline": "ep-unlocked", "type": "event"}, {"slugline": "ep-e-locked", "type": "event"}, - {"slugline": "ep-p-locked", "type": "event"} + {"slugline": "ep-p-locked", "type": "event"}, + {"slugline": "ep-unlocked", "type": "planning"}, + {"slugline": "ep-e-locked", "type": "planning"}, + {"slugline": "ep-p-locked", "type": "planning"} ]} """ When we get "/events_planning_search?only_future=false&lock_state=unlocked" diff --git a/server/features/search_sort.feature b/server/features/search_sort.feature index f30da10e5..c5a07ac5a 100644 --- a/server/features/search_sort.feature +++ b/server/features/search_sort.feature @@ -147,31 +147,31 @@ Feature: Event Search When we get "events_planning_search?repo=combined&only_future=false" Then we get the following order """ - ["event_2", "event_4", "event_1", "plan_1", "event_3", "plan_3"] + ["event_2", "plan_2", "event_4", "plan_4", "event_1", "plan_1", "event_3", "plan_3"] """ # Sort by creation date, in ascending order (default order) When we get "events_planning_search?repo=combined&only_future=false&sort_field=created" Then we get the following order """ - ["event_1", "plan_1", "event_2", "event_3", "plan_3", "event_4"] + ["event_1", "plan_1", "event_2", "plan_2", "event_3", "plan_3", "event_4", "plan_4"] """ # Sort by creation date, in descending order When we get "events_planning_search?repo=combined&only_future=false&sort_field=created&sort_order=descending" Then we get the following order """ - ["event_4", "plan_3", "event_3", "event_2", "plan_1", "event_1"] + ["plan_4", "event_4", "plan_3", "event_3", "plan_2", "event_2", "plan_1", "event_1"] """ # Sort by updated date, in ascending order (default order) When we get "events_planning_search?repo=combined&only_future=false&sort_field=updated" Then we get the following order """ - ["event_4", "event_3", "plan_3", "event_2", "event_1", "plan_1"] + ["event_4", "plan_4", "event_3", "plan_3", "event_2", "plan_2", "event_1", "plan_1"] """ # Sort by updated date, in descending order When we get "events_planning_search?repo=combined&only_future=false&sort_field=updated&sort_order=descending" Then we get the following order """ - ["plan_1", "event_1", "event_2", "plan_3", "event_3", "event_4"] + ["plan_1", "event_1", "plan_2", "event_2", "plan_3", "event_3", "plan_4", "event_4"] """ # Update an item, then sort by updated date in descending order When we patch "/events/event_3" @@ -181,5 +181,5 @@ Feature: Event Search When we get "events_planning_search?repo=combined&only_future=false&sort_field=updated&sort_order=descending" Then we get the following order """ - ["event_3", "plan_1", "event_1", "event_2", "plan_3", "event_4"] + ["event_3", "plan_1", "event_1", "plan_2", "event_2", "plan_3", "plan_4", "event_4"] """ diff --git a/server/planning/search/eventsplanning_search.py b/server/planning/search/eventsplanning_search.py index f54e3de1f..b21f257c7 100644 --- a/server/planning/search/eventsplanning_search.py +++ b/server/planning/search/eventsplanning_search.py @@ -29,11 +29,7 @@ from .queries.planning import PLANNING_PARAMS, PLANNING_SEARCH_FILTERS from .queries.events import EVENT_PARAMS, EVENT_SEARCH_FILTERS -from .queries.combined import ( - COMBINED_PARAMS, - COMBINED_SEARCH_FILTERS, - construct_combined_view_data_query, -) +from .queries.combined import COMBINED_PARAMS, COMBINED_SEARCH_FILTERS from .queries.common import construct_search_query from .queries.elastic import ElasticQuery, field_exists @@ -66,13 +62,11 @@ def get(self, req, lookup): query = self._construct_search_query(repo, params, search_filter) if repo == "events" or repo == "event": - items = self._search_events(req, params, query, search_filter) - return self._get_combined_view_data(items, req, params, search_filter) + return self._search_events(req, params, query, search_filter) elif repo == "planning": return self._search_planning(req, params, query, search_filter) else: - items = self._get_events_and_planning(req, query, search_filter) - return self._get_combined_view_data(items, req, params, search_filter) + return self._get_events_and_planning(req, params, query, search_filter) def on_fetched(self, doc): """ @@ -126,13 +120,12 @@ def _construct_search_query( return construct_search_query(repo, filters, params, search_filter) - def _get_combined_view_data(self, items, request, params, search_filter): - """Get list of event and planning for the combined view + def _get_events_and_planning(self, request, params, query, search_filter): + """Get list of event and planning based on the search criteria - :param items: :param request: object representing the HTTP request """ - query = construct_combined_view_data_query(params, search_filter, items) + page = request.page or 1 page_size = self._get_page_size(request, search_filter) req = ParsedRequest() @@ -145,36 +138,12 @@ def _get_combined_view_data(self, items, request, params, search_filter): "from": (page - 1) * page_size, } ) - req.page = request.page or 1 + req.page = page req.max_results = page_size if params.get("projections"): req.args["projections"] = params["projections"] return get_resource_service("planning_search").get(req=req, lookup=None) - def _get_events_and_planning(self, request, query, search_filter): - """Get list of event and planning based on the search criteria - - :param request: object representing the HTTP request - """ - # params = request.args or MultiDict() - # query = construct_combined_search_query(params) - page = request.page or 1 - max_results = self._get_page_size(request, search_filter) - req = ParsedRequest() - req.args = MultiDict() - req.args["source"] = json.dumps( - { - "query": query["query"], - "sort": query["sort"] if query.get("sort") else self._get_sort(), - "size": int((5 * max_results) * math.ceil(page / 3)), - } - ) - req.args["projections"] = json.dumps(["_id", "type", "related_events"]) - req.page = page - req.max_results = max_results - req.exec_on_fetched_resource = False # don't call on_fetched_resource - return get_resource_service("planning_search").get(req=req, lookup=None) - def _search_events(self, request, params, query, search_filter): page = request.page or 1 page_size = self._get_page_size(request, search_filter) diff --git a/server/planning/search/queries/combined.py b/server/planning/search/queries/combined.py index 53458040c..e798813cc 100644 --- a/server/planning/search/queries/combined.py +++ b/server/planning/search/queries/combined.py @@ -10,46 +10,7 @@ from typing import Dict, Any, List, Callable -from planning.utils import get_related_event_ids_for_planning from planning.search.queries import elastic, events, planning, common -from flask import current_app as app - - -def construct_combined_view_data_query( - params: Dict[str, Any], search_filter: Dict[str, Any], items: List[Dict[str, Any]] -) -> Dict[str, Any]: - ids = set() - for item in items: - item_id = item.get("_id") - event_ids = get_related_event_ids_for_planning(item, "primary") - if common.strtobool(params.get("include_associated_planning", False)): - ids.add(item_id) - for event_id in event_ids: - ids.add(event_id) - else: - # Combined search prioritises Events over Planning items - # therefore if the Planning item is linked to an Event - # then we want to return that Event instead - if len(event_ids): - for event_id in event_ids: - ids.add(event_id) - else: - ids.add(item_id) - - query = elastic.ElasticQuery() - - filter_params = common.get_params_from_search_filter(search_filter) - if len(filter_params): - filter_params["time_zone"] = params.get("time_zone") or app.config.get("DEFAULT_TIMEZONE") - filter_params["start_of_week"] = params.get("start_of_week", app.config.get("START_OF_WEEK", 0)) - - search_dates(filter_params, query) - - search_dates(params, query) - - query.must.append(elastic.terms(field="_id", values=list(ids))) - - return query.build() def search_not_common_fields(params: Dict[str, Any], query: elastic.ElasticQuery): diff --git a/server/planning/tests/utils_tests.py b/server/planning/tests/utils_tests.py index 43c05b74b..4fd5057bb 100644 --- a/server/planning/tests/utils_tests.py +++ b/server/planning/tests/utils_tests.py @@ -1,3 +1,5 @@ +import pytz + from planning.tests import TestCase from datetime import datetime from planning.utils import get_event_formatted_dates @@ -6,29 +8,29 @@ class TestGetEventFormattedDates(TestCase): def test_multi_day_event(self): - start = datetime(2024, 5, 28, 5, 00, 00) - end = datetime(2024, 5, 29, 6, 00, 00) + start = datetime(2024, 5, 28, 5, 00, 00, tzinfo=pytz.UTC) + end = datetime(2024, 5, 29, 6, 00, 00, tzinfo=pytz.UTC) event = {"dates": {"start": start, "end": end, "tz": "Asia/Calcutta"}} result = get_event_formatted_dates(event) self.assertEqual(result, "10:30 28/05/2024 - 11:30 29/05/2024") def test_all_day_event(self): - start = datetime(2024, 4, 27, 18, 30, 00) - end = datetime(2024, 4, 28, 18, 29, 59) + start = datetime(2024, 4, 27, 18, 30, 00, tzinfo=pytz.UTC) + end = datetime(2024, 4, 28, 18, 29, 59, tzinfo=pytz.UTC) event = {"dates": {"start": start, "end": end, "tz": "Asia/Calcutta"}} result = get_event_formatted_dates(event) self.assertEqual(result, "ALL DAY 28/04/2024") def test_same_start_end(self): - start = datetime(2024, 4, 1, 14, 45) - end = datetime(2024, 4, 1, 14, 45) + start = datetime(2024, 4, 1, 14, 45, tzinfo=pytz.UTC) + end = datetime(2024, 4, 1, 14, 45, tzinfo=pytz.UTC) event = {"dates": {"start": start, "end": end, "tz": "Asia/Calcutta"}} result = get_event_formatted_dates(event) self.assertEqual(result, "20:15 01/04/2024") def test_dates_same_and_different_time(self): - start = datetime(2024, 5, 28, 5, 00, 00) - end = datetime(2024, 5, 28, 6, 00, 00) + start = datetime(2024, 5, 28, 5, 00, 00, tzinfo=pytz.UTC) + end = datetime(2024, 5, 28, 6, 00, 00, tzinfo=pytz.UTC) event = {"dates": {"start": start, "end": end, "tz": "Asia/Calcutta"}} result = get_event_formatted_dates(event) self.assertEqual(result, "10:30 - 11:30, 28/05/2024")