diff --git a/doc/api/resources/events.rst b/doc/api/resources/events.rst index cc22588ca2..e7acc8a8a5 100644 --- a/doc/api/resources/events.rst +++ b/doc/api/resources/events.rst @@ -88,6 +88,8 @@ Endpoints The ``with_availability_for`` parameter has been added. + The ``search`` query parameter has been added to filter events by their slug, name, or location in any language. + .. http:get:: /api/v1/organizers/(organizer)/events/ Returns a list of all events within a given organizer the authenticated user/token has access to. @@ -170,6 +172,7 @@ Endpoints attribute with values of 100 for "tickets available", values less than 100 for "tickets sold out or reserved", and ``null`` for "status unknown". These values might be served from a cache. This parameter can make the response slow. + :query search: Only return events matching a given search query. :param organizer: The ``slug`` field of a valid organizer :statuscode 200: no error :statuscode 401: Authentication failure diff --git a/src/pretix/api/views/event.py b/src/pretix/api/views/event.py index 155dd803bb..51d802983b 100644 --- a/src/pretix/api/views/event.py +++ b/src/pretix/api/views/event.py @@ -55,15 +55,18 @@ from pretix.base.models.event import SubEvent from pretix.base.services.quotas import QuotaAvailability from pretix.base.settings import SETTINGS_AFFECTING_CSS from pretix.helpers.dicts import merge_dicts +from pretix.helpers.i18n import i18ncomp from pretix.presale.style import regenerate_css from pretix.presale.views.organizer import filter_qs_by_attr with scopes_disabled(): class EventFilter(FilterSet): + is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs') is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs') ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs') sales_channel = django_filters.rest_framework.CharFilter(method='sales_channel_qs') + search = django_filters.rest_framework.CharFilter(method='search_qs') class Meta: model = Event @@ -108,6 +111,13 @@ with scopes_disabled(): def sales_channel_qs(self, queryset, name, value): return queryset.filter(sales_channels__contains=value) + def search_qs(self, queryset, name, value): + return queryset.filter( + Q(name__icontains=i18ncomp(value)) + | Q(slug__icontains=value) + | Q(location__icontains=i18ncomp(value)) + ) + class EventViewSet(viewsets.ModelViewSet): serializer_class = EventSerializer diff --git a/src/tests/api/test_events.py b/src/tests/api/test_events.py index 7f766a29a0..f9bca368c4 100644 --- a/src/tests/api/test_events.py +++ b/src/tests/api/test_events.py @@ -193,6 +193,17 @@ def test_event_list_filter(token_client, organizer, event): assert resp.data['count'] == 0 +@pytest.mark.django_db +def test_event_list_name_filter(token_client, organizer, event): + resp = token_client.get('/api/v1/organizers/{}/events/?search=Dummy'.format(organizer.slug)) + assert resp.status_code == 200 + assert resp.data['count'] == 1 + + resp = token_client.get('/api/v1/organizers/{}/events/?search=notdummy'.format(organizer.slug)) + assert resp.status_code == 200 + assert resp.data['count'] == 0 + + @pytest.mark.django_db def test_event_get(token_client, organizer, event): resp = token_client.get('/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug))