diff --git a/doc/api/resources/events.rst b/doc/api/resources/events.rst index f4ef10e9a..8ce6bc9e2 100644 --- a/doc/api/resources/events.rst +++ b/doc/api/resources/events.rst @@ -77,6 +77,10 @@ seat_category_mapping object An object mappi Endpoints --------- +.. versionchanged:: 3.3 + + The events resource can now be filtered by meta data attributes. + .. http:get:: /api/v1/organizers/(organizer)/events/ Returns a list of all events within a given organizer the authenticated user/token has access to. @@ -143,6 +147,10 @@ Endpoints :query string ordering: Manually set the ordering of results. Valid fields to be used are ``date_from`` and ``slug``. Keep in mind that ``date_from`` of event series does not really tell you anything. Default: ``slug``. + :query array attr[meta_data_key]: By providing the key and value of a meta data attribute, the list of events will + only contain the events matching the set criteria. Providing ``?attr[Format]=Seminar`` would return only those + events having set their ``Format`` meta data to ``Seminar``, ``?attr[Format]=`` only those, that have no value + set. Please note that this filter will respect default values set on organizer level. :param organizer: The ``slug`` field of a valid organizer :statuscode 200: no error :statuscode 401: Authentication failure diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst index a4de20464..cdf7f98ee 100644 --- a/doc/api/resources/orders.rst +++ b/doc/api/resources/orders.rst @@ -131,16 +131,16 @@ last_modified datetime Last modificati The ``sales_channel`` attribute has been added. -.. versionchanged:: 2.4: +.. versionchanged:: 2.4 ``order.status`` can no longer be ``r``, ``…/mark_canceled/`` now accepts a ``cancellation_fee`` parameter and ``…/mark_refunded/`` has been deprecated. -.. versionchanged:: 2.5: +.. versionchanged:: 2.5 The ``testmode`` attribute has been added and ``DELETE`` has been implemented for orders. -.. versionchanged:: 3.1: +.. versionchanged:: 3.1 The ``invoice_address.state`` and ``url`` attributes have been added. When creating orders through the API, vouchers are now supported and many fields are now optional. diff --git a/doc/api/resources/subevents.rst b/doc/api/resources/subevents.rst index ee4d5c9a3..2edb982a1 100644 --- a/doc/api/resources/subevents.rst +++ b/doc/api/resources/subevents.rst @@ -77,6 +77,10 @@ seat_category_mapping object An object mappi Endpoints --------- +.. versionchanged:: 3.3 + + The sub-events resource can now be filtered by meta data attributes. + .. http:get:: /api/v1/organizers/(organizer)/events/(event)/subevents/ Returns a list of all sub-events of an event. @@ -137,6 +141,11 @@ Endpoints :query ends_after: If set to a date and time, only events that happen during of after the given time are returned. :param organizer: The ``slug`` field of a valid organizer :param event: The ``slug`` field of the main event + :query array attr[meta_data_key]: By providing the key and value of a meta data attribute, the list of sub-events + will only contain the sub-events matching the set criteria. Providing ``?attr[Format]=Seminar`` would return + only those sub-events having set their ``Format`` meta data to ``Seminar``, ``?attr[Format]=`` only those, that + have no value set. Please note that this filter will respect default values set on + organizer or event level. :statuscode 200: no error :statuscode 401: Authentication failure :statuscode 403: The requested organizer does not exist **or** you have no permission to view it. diff --git a/src/pretix/api/views/event.py b/src/pretix/api/views/event.py index eb8363133..282b9f782 100644 --- a/src/pretix/api/views/event.py +++ b/src/pretix/api/views/event.py @@ -18,6 +18,7 @@ from pretix.base.models import ( ) from pretix.base.models.event import SubEvent from pretix.helpers.dicts import merge_dicts +from pretix.presale.views.organizer import filter_qs_by_attr with scopes_disabled(): class EventFilter(FilterSet): @@ -85,6 +86,8 @@ class EventViewSet(viewsets.ModelViewSet): organizer=self.request.organizer ) + qs = filter_qs_by_attr(qs, self.request) + return qs.prefetch_related( 'meta_values', 'meta_values__property', 'seat_category_mappings' ) @@ -241,6 +244,9 @@ class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet): event__organizer=self.request.organizer, event__in=self.request.user.get_events_with_any_permission() ) + + qs = filter_qs_by_attr(qs, self.request) + return qs.prefetch_related( 'subeventitem_set', 'subeventitemvariation_set', 'seat_category_mappings' ) diff --git a/src/tests/api/test_events.py b/src/tests/api/test_events.py index 7362b2fdf..d768877ed 100644 --- a/src/tests/api/test_events.py +++ b/src/tests/api/test_events.py @@ -135,6 +135,17 @@ def test_event_list(token_client, organizer, event): assert [TEST_EVENT_RES] == resp.data['results'] +@pytest.mark.django_db +def test_event_list_filter(token_client, organizer, event): + resp = token_client.get('/api/v1/organizers/{}/events/?attr[type]=Conference'.format(organizer.slug)) + assert resp.status_code == 200 + assert resp.data['count'] == 1 + + resp = token_client.get('/api/v1/organizers/{}/events/?attr[type]='.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)) diff --git a/src/tests/api/test_subevents.py b/src/tests/api/test_subevents.py index 101e2e49a..31659aafb 100644 --- a/src/tests/api/test_subevents.py +++ b/src/tests/api/test_subevents.py @@ -130,6 +130,17 @@ def test_subevent_list(token_client, organizer, event, subevent): assert [] == resp.data['results'] +@pytest.mark.django_db +def test_subevent_list_filter(token_client, organizer, event, subevent): + resp = token_client.get('/api/v1/organizers/{}/events/{}/subevents/?attr[type]=Workshop'.format(organizer.slug, event.slug)) + assert resp.status_code == 200 + assert resp.data['count'] == 1 + + resp = token_client.get('/api/v1/organizers/{}/events/{}/subevents/?attr[type]=Conference'.format(organizer.slug, event.slug)) + assert resp.status_code == 200 + assert resp.data['count'] == 0 + + @pytest.mark.django_db def test_subevent_get(token_client, organizer, event, subevent): res = dict(TEST_SUBEVENT_RES)