We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Handle invalid filter values
### Describe the bug
https://thalia.sentry.io/issues/4448548023/?project=1463433&query=is%3Aunresolved+issue.category%3Aerror&referrer=issue-stream&stream_index=8

When passing e.g. "foo" to a boolean filter in some API views, you get 500 Internal Server Error, not 400 Bad Request.

### How to reproduce
Steps to reproduce the behaviour:
1. Go to `https://staging.thalia.nu/api/v2/admin/events/183/registrations/?queued=all`

### Expected behaviour
400


_Note that there are more such filters. Let's fix them all, not just this single one._

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `website/payments/api/v2/filters.py`
Content:
```
1 from rest_framework import filters
2 
3 from utils.snippets import extract_date_range, strtobool
4 
5 
6 class CreatedAtFilter(filters.BaseFilterBackend):
7     """Allows you to filter by payment creation dates."""
8 
9     def filter_queryset(self, request, queryset, view):
10         start, end = extract_date_range(request, allow_empty=True)
11 
12         if start is not None:
13             queryset = queryset.filter(created_at__gte=start)
14         if end is not None:
15             queryset = queryset.filter(created_at__lte=end)
16 
17         return queryset
18 
19     def get_schema_operation_parameters(self, view):
20         return [
21             {
22                 "name": "start",
23                 "required": False,
24                 "in": "query",
25                 "description": "Filter payments by ISO date, starting with this parameter (i.e. 2021-03-30T04:20:00) where `payment.created_at >= value`",
26                 "schema": {
27                     "type": "string",
28                 },
29             },
30             {
31                 "name": "end",
32                 "required": False,
33                 "in": "query",
34                 "description": "Filter payments by ISO date, ending with this parameter (i.e. 2021-05-16T13:37:00) where `payment.created_at <= value`",
35                 "schema": {
36                     "type": "string",
37                 },
38             },
39         ]
40 
41 
42 class PaymentTypeFilter(filters.BaseFilterBackend):
43     """Allows you to filter by payment type."""
44 
45     def filter_queryset(self, request, queryset, view):
46         payment_type = request.query_params.get("type", None)
47 
48         if payment_type:
49             queryset = queryset.filter(type__in=payment_type.split(","))
50 
51         return queryset
52 
53     def get_schema_operation_parameters(self, view):
54         return [
55             {
56                 "name": "type",
57                 "required": False,
58                 "in": "query",
59                 "description": "Filter by payment type, accepts a comma separated list",
60                 "schema": {
61                     "type": "string",
62                 },
63             }
64         ]
65 
66 
67 class PaymentSettledFilter(filters.BaseFilterBackend):
68     """Allows you to filter by settled status."""
69 
70     def filter_queryset(self, request, queryset, view):
71         settled = request.query_params.get("settled", None)
72 
73         if settled is None:
74             return queryset
75 
76         if strtobool(settled):
77             return queryset.filter(batch__processed=True)
78 
79         return queryset.exclude(batch__processed=True)
80 
81     def get_schema_operation_parameters(self, view):
82         return [
83             {
84                 "name": "settled",
85                 "required": False,
86                 "in": "query",
87                 "description": "Filter by settled status",
88                 "schema": {
89                     "type": "boolean",
90                 },
91             }
92         ]
93
```

Path: `website/sales/api/v2/filters.py`
Content:
```
1 from rest_framework import filters
2 
3 from utils.snippets import extract_date_range, strtobool
4 
5 
6 class ShiftActiveFilter(filters.BaseFilterBackend):
7     """Allows you to filter by active status."""
8 
9     def filter_queryset(self, request, queryset, view):
10         active = request.query_params.get("active", None)
11 
12         if active is not None:
13             queryset = queryset.filter(active=strtobool(active))
14 
15         return queryset
16 
17     def get_schema_operation_parameters(self, view):
18         return [
19             {
20                 "name": "active",
21                 "required": False,
22                 "in": "query",
23                 "description": "Filter by active status",
24                 "schema": {
25                     "type": "boolean",
26                 },
27             }
28         ]
29 
30 
31 class ShiftLockedFilter(filters.BaseFilterBackend):
32     """Allows you to filter by locked status."""
33 
34     def filter_queryset(self, request, queryset, view):
35         locked = request.query_params.get("locked", None)
36 
37         if locked is not None:
38             queryset = queryset.filter(locked=strtobool(locked))
39 
40         return queryset
41 
42     def get_schema_operation_parameters(self, view):
43         return [
44             {
45                 "name": "locked",
46                 "required": False,
47                 "in": "query",
48                 "description": "Filter by locked status",
49                 "schema": {
50                     "type": "boolean",
51                 },
52             }
53         ]
54 
55 
56 class ShiftDateFilter(filters.BaseFilterBackend):
57     """Allows you to filter by event start/end dates."""
58 
59     def filter_queryset(self, request, queryset, view):
60         start, end = extract_date_range(request, allow_empty=True)
61 
62         if start is not None:
63             queryset = queryset.filter(end__gte=start)
64         if end is not None:
65             queryset = queryset.filter(start__lte=end)
66 
67         return queryset
68 
69     def get_schema_operation_parameters(self, view):
70         return [
71             {
72                 "name": "start",
73                 "required": False,
74                 "in": "query",
75                 "description": "Filter shifts by ISO date, starting with this parameter (i.e. 2021-03-30T04:20:00) where `event.end >= value`",
76                 "schema": {
77                     "type": "string",
78                 },
79             },
80             {
81                 "name": "end",
82                 "required": False,
83                 "in": "query",
84                 "description": "Filter shifts by ISO date, ending with this parameter (i.e. 2021-05-16T13:37:00) where `event.start <= value`",
85                 "schema": {
86                     "type": "string",
87                 },
88             },
89         ]
90
```

Path: `website/events/api/v2/admin/filters.py`
Content:
```
1 from rest_framework import filters
2 
3 from utils.snippets import strtobool
4 
5 
6 class PublishedFilter(filters.BaseFilterBackend):
7     """Allows you to filter by published status."""
8 
9     def filter_queryset(self, request, queryset, view):
10         published = request.query_params.get("published", None)
11 
12         if published is not None:
13             queryset = queryset.filter(published=strtobool(published))
14 
15         return queryset
16 
17     def get_schema_operation_parameters(self, view):
18         return [
19             {
20                 "name": "published",
21                 "required": False,
22                 "in": "query",
23                 "description": "Filter by published status",
24                 "schema": {
25                     "type": "boolean",
26                 },
27             }
28         ]
29 
30 
31 class EventRegistrationCancelledFilter(filters.BaseFilterBackend):
32     """Allows you to filter by event registration cancellation status."""
33 
34     def filter_queryset(self, request, queryset, view):
35         cancelled = request.query_params.get("cancelled", None)
36 
37         if cancelled is None:
38             return queryset
39 
40         if strtobool(cancelled):
41             return queryset.exclude(date_cancelled=None)
42 
43         return queryset.filter(date_cancelled=None)
44 
45     def get_schema_operation_parameters(self, view):
46         return [
47             {
48                 "name": "cancelled",
49                 "required": False,
50                 "in": "query",
51                 "description": "Filter by event registration cancellation status",
52                 "schema": {
53                     "type": "boolean",
54                 },
55             }
56         ]
57 
58 
59 class EventRegistrationQueuedFilter(filters.BaseFilterBackend):
60     """Allows you to filter by event registration by if they're in the queue."""
61 
62     def filter_queryset(self, request, queryset, view):
63         queued = request.query_params.get("queued", None)
64 
65         if queued is None:
66             return queryset
67 
68         if strtobool(queued):
69             return queryset.exclude(queue_position=None)
70 
71         return queryset.filter(queue_position=None)
72 
73     def get_schema_operation_parameters(self, view):
74         return [
75             {
76                 "name": "queued",
77                 "required": False,
78                 "in": "query",
79                 "description": "Filter by event registration queue position",
80                 "schema": {
81                     "type": "boolean",
82                 },
83             }
84         ]
85
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/website/events/api/v2/admin/filters.py b/website/events/api/v2/admin/filters.py
--- a/website/events/api/v2/admin/filters.py
+++ b/website/events/api/v2/admin/filters.py
@@ -1,4 +1,5 @@
 from rest_framework import filters
+from rest_framework.exceptions import ValidationError
 
 from utils.snippets import strtobool
 
@@ -10,7 +11,10 @@
         published = request.query_params.get("published", None)
 
         if published is not None:
-            queryset = queryset.filter(published=strtobool(published))
+            try:
+                queryset = queryset.filter(published=strtobool(published))
+            except ValueError as e:
+                raise ValidationError({"published": "Invalid filter value."}) from e
 
         return queryset
 
@@ -37,8 +41,11 @@
         if cancelled is None:
             return queryset
 
-        if strtobool(cancelled):
-            return queryset.exclude(date_cancelled=None)
+        try:
+            if strtobool(cancelled):
+                return queryset.exclude(date_cancelled=None)
+        except ValueError as e:
+            raise ValidationError({"cancelled": "Invalid filter value."}) from e
 
         return queryset.filter(date_cancelled=None)
 
@@ -65,8 +72,11 @@
         if queued is None:
             return queryset
 
-        if strtobool(queued):
-            return queryset.exclude(queue_position=None)
+        try:
+            if strtobool(queued):
+                return queryset.exclude(queue_position=None)
+        except ValueError as e:
+            raise ValidationError({"queued": "Invalid filter value."}) from e
 
         return queryset.filter(queue_position=None)
 
diff --git a/website/payments/api/v2/filters.py b/website/payments/api/v2/filters.py
--- a/website/payments/api/v2/filters.py
+++ b/website/payments/api/v2/filters.py
@@ -1,4 +1,5 @@
 from rest_framework import filters
+from rest_framework.exceptions import ValidationError
 
 from utils.snippets import extract_date_range, strtobool
 
@@ -73,8 +74,11 @@
         if settled is None:
             return queryset
 
-        if strtobool(settled):
-            return queryset.filter(batch__processed=True)
+        try:
+            if strtobool(settled):
+                return queryset.filter(batch__processed=True)
+        except ValueError as e:
+            raise ValidationError({"settled": "Invalid filter value."}) from e
 
         return queryset.exclude(batch__processed=True)
 
diff --git a/website/sales/api/v2/filters.py b/website/sales/api/v2/filters.py
--- a/website/sales/api/v2/filters.py
+++ b/website/sales/api/v2/filters.py
@@ -1,4 +1,5 @@
 from rest_framework import filters
+from rest_framework.exceptions import ValidationError
 
 from utils.snippets import extract_date_range, strtobool
 
@@ -10,7 +11,10 @@
         active = request.query_params.get("active", None)
 
         if active is not None:
-            queryset = queryset.filter(active=strtobool(active))
+            try:
+                queryset = queryset.filter(active=strtobool(active))
+            except ValueError as e:
+                raise ValidationError({"active": "Invalid filter value."}) from e
 
         return queryset
 
@@ -35,7 +39,10 @@
         locked = request.query_params.get("locked", None)
 
         if locked is not None:
-            queryset = queryset.filter(locked=strtobool(locked))
+            try:
+                queryset = queryset.filter(locked=strtobool(locked))
+            except ValueError as e:
+                raise ValidationError({"locked": "Invalid filter value."}) from e
 
         return queryset

{"golden_diff": "diff --git a/website/events/api/v2/admin/filters.py b/website/events/api/v2/admin/filters.py\n--- a/website/events/api/v2/admin/filters.py\n+++ b/website/events/api/v2/admin/filters.py\n@@ -1,4 +1,5 @@\n from rest_framework import filters\n+from rest_framework.exceptions import ValidationError\n \n from utils.snippets import strtobool\n \n@@ -10,7 +11,10 @@\n         published = request.query_params.get(\"published\", None)\n \n         if published is not None:\n-            queryset = queryset.filter(published=strtobool(published))\n+            try:\n+                queryset = queryset.filter(published=strtobool(published))\n+            except ValueError as e:\n+                raise ValidationError({\"published\": \"Invalid filter value.\"}) from e\n \n         return queryset\n \n@@ -37,8 +41,11 @@\n         if cancelled is None:\n             return queryset\n \n-        if strtobool(cancelled):\n-            return queryset.exclude(date_cancelled=None)\n+        try:\n+            if strtobool(cancelled):\n+                return queryset.exclude(date_cancelled=None)\n+        except ValueError as e:\n+            raise ValidationError({\"cancelled\": \"Invalid filter value.\"}) from e\n \n         return queryset.filter(date_cancelled=None)\n \n@@ -65,8 +72,11 @@\n         if queued is None:\n             return queryset\n \n-        if strtobool(queued):\n-            return queryset.exclude(queue_position=None)\n+        try:\n+            if strtobool(queued):\n+                return queryset.exclude(queue_position=None)\n+        except ValueError as e:\n+            raise ValidationError({\"queued\": \"Invalid filter value.\"}) from e\n \n         return queryset.filter(queue_position=None)\n \ndiff --git a/website/payments/api/v2/filters.py b/website/payments/api/v2/filters.py\n--- a/website/payments/api/v2/filters.py\n+++ b/website/payments/api/v2/filters.py\n@@ -1,4 +1,5 @@\n from rest_framework import filters\n+from rest_framework.exceptions import ValidationError\n \n from utils.snippets import extract_date_range, strtobool\n \n@@ -73,8 +74,11 @@\n         if settled is None:\n             return queryset\n \n-        if strtobool(settled):\n-            return queryset.filter(batch__processed=True)\n+        try:\n+            if strtobool(settled):\n+                return queryset.filter(batch__processed=True)\n+        except ValueError as e:\n+            raise ValidationError({\"settled\": \"Invalid filter value.\"}) from e\n \n         return queryset.exclude(batch__processed=True)\n \ndiff --git a/website/sales/api/v2/filters.py b/website/sales/api/v2/filters.py\n--- a/website/sales/api/v2/filters.py\n+++ b/website/sales/api/v2/filters.py\n@@ -1,4 +1,5 @@\n from rest_framework import filters\n+from rest_framework.exceptions import ValidationError\n \n from utils.snippets import extract_date_range, strtobool\n \n@@ -10,7 +11,10 @@\n         active = request.query_params.get(\"active\", None)\n \n         if active is not None:\n-            queryset = queryset.filter(active=strtobool(active))\n+            try:\n+                queryset = queryset.filter(active=strtobool(active))\n+            except ValueError as e:\n+                raise ValidationError({\"active\": \"Invalid filter value.\"}) from e\n \n         return queryset\n \n@@ -35,7 +39,10 @@\n         locked = request.query_params.get(\"locked\", None)\n \n         if locked is not None:\n-            queryset = queryset.filter(locked=strtobool(locked))\n+            try:\n+                queryset = queryset.filter(locked=strtobool(locked))\n+            except ValueError as e:\n+                raise ValidationError({\"locked\": \"Invalid filter value.\"}) from e\n \n         return queryset\n", "issue": "Handle invalid filter values\n### Describe the bug\r\nhttps://thalia.sentry.io/issues/4448548023/?project=1463433&query=is%3Aunresolved+issue.category%3Aerror&referrer=issue-stream&stream_index=8\r\n\r\nWhen passing e.g. \"foo\" to a boolean filter in some API views, you get 500 Internal Server Error, not 400 Bad Request.\r\n\r\n### How to reproduce\r\nSteps to reproduce the behaviour:\r\n1. Go to `https://staging.thalia.nu/api/v2/admin/events/183/registrations/?queued=all`\r\n\r\n### Expected behaviour\r\n400\r\n\r\n\r\n_Note that there are more such filters. Let's fix them all, not just this single one._\n", "before_files": [{"content": "from rest_framework import filters\n\nfrom utils.snippets import extract_date_range, strtobool\n\n\nclass CreatedAtFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by payment creation dates.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        start, end = extract_date_range(request, allow_empty=True)\n\n        if start is not None:\n            queryset = queryset.filter(created_at__gte=start)\n        if end is not None:\n            queryset = queryset.filter(created_at__lte=end)\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"start\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter payments by ISO date, starting with this parameter (i.e. 2021-03-30T04:20:00) where `payment.created_at >= value`\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            },\n            {\n                \"name\": \"end\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter payments by ISO date, ending with this parameter (i.e. 2021-05-16T13:37:00) where `payment.created_at <= value`\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            },\n        ]\n\n\nclass PaymentTypeFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by payment type.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        payment_type = request.query_params.get(\"type\", None)\n\n        if payment_type:\n            queryset = queryset.filter(type__in=payment_type.split(\",\"))\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"type\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by payment type, accepts a comma separated list\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            }\n        ]\n\n\nclass PaymentSettledFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by settled status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        settled = request.query_params.get(\"settled\", None)\n\n        if settled is None:\n            return queryset\n\n        if strtobool(settled):\n            return queryset.filter(batch__processed=True)\n\n        return queryset.exclude(batch__processed=True)\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"settled\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by settled status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n", "path": "website/payments/api/v2/filters.py"}, {"content": "from rest_framework import filters\n\nfrom utils.snippets import extract_date_range, strtobool\n\n\nclass ShiftActiveFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by active status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        active = request.query_params.get(\"active\", None)\n\n        if active is not None:\n            queryset = queryset.filter(active=strtobool(active))\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"active\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by active status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n\n\nclass ShiftLockedFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by locked status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        locked = request.query_params.get(\"locked\", None)\n\n        if locked is not None:\n            queryset = queryset.filter(locked=strtobool(locked))\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"locked\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by locked status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n\n\nclass ShiftDateFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by event start/end dates.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        start, end = extract_date_range(request, allow_empty=True)\n\n        if start is not None:\n            queryset = queryset.filter(end__gte=start)\n        if end is not None:\n            queryset = queryset.filter(start__lte=end)\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"start\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter shifts by ISO date, starting with this parameter (i.e. 2021-03-30T04:20:00) where `event.end >= value`\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            },\n            {\n                \"name\": \"end\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter shifts by ISO date, ending with this parameter (i.e. 2021-05-16T13:37:00) where `event.start <= value`\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            },\n        ]\n", "path": "website/sales/api/v2/filters.py"}, {"content": "from rest_framework import filters\n\nfrom utils.snippets import strtobool\n\n\nclass PublishedFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by published status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        published = request.query_params.get(\"published\", None)\n\n        if published is not None:\n            queryset = queryset.filter(published=strtobool(published))\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"published\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by published status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n\n\nclass EventRegistrationCancelledFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by event registration cancellation status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        cancelled = request.query_params.get(\"cancelled\", None)\n\n        if cancelled is None:\n            return queryset\n\n        if strtobool(cancelled):\n            return queryset.exclude(date_cancelled=None)\n\n        return queryset.filter(date_cancelled=None)\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"cancelled\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by event registration cancellation status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n\n\nclass EventRegistrationQueuedFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by event registration by if they're in the queue.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        queued = request.query_params.get(\"queued\", None)\n\n        if queued is None:\n            return queryset\n\n        if strtobool(queued):\n            return queryset.exclude(queue_position=None)\n\n        return queryset.filter(queue_position=None)\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"queued\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by event registration queue position\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n", "path": "website/events/api/v2/admin/filters.py"}], "after_files": [{"content": "from rest_framework import filters\nfrom rest_framework.exceptions import ValidationError\n\nfrom utils.snippets import extract_date_range, strtobool\n\n\nclass CreatedAtFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by payment creation dates.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        start, end = extract_date_range(request, allow_empty=True)\n\n        if start is not None:\n            queryset = queryset.filter(created_at__gte=start)\n        if end is not None:\n            queryset = queryset.filter(created_at__lte=end)\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"start\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter payments by ISO date, starting with this parameter (i.e. 2021-03-30T04:20:00) where `payment.created_at >= value`\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            },\n            {\n                \"name\": \"end\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter payments by ISO date, ending with this parameter (i.e. 2021-05-16T13:37:00) where `payment.created_at <= value`\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            },\n        ]\n\n\nclass PaymentTypeFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by payment type.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        payment_type = request.query_params.get(\"type\", None)\n\n        if payment_type:\n            queryset = queryset.filter(type__in=payment_type.split(\",\"))\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"type\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by payment type, accepts a comma separated list\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            }\n        ]\n\n\nclass PaymentSettledFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by settled status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        settled = request.query_params.get(\"settled\", None)\n\n        if settled is None:\n            return queryset\n\n        try:\n            if strtobool(settled):\n                return queryset.filter(batch__processed=True)\n        except ValueError as e:\n            raise ValidationError({\"settled\": \"Invalid filter value.\"}) from e\n\n        return queryset.exclude(batch__processed=True)\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"settled\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by settled status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n", "path": "website/payments/api/v2/filters.py"}, {"content": "from rest_framework import filters\nfrom rest_framework.exceptions import ValidationError\n\nfrom utils.snippets import extract_date_range, strtobool\n\n\nclass ShiftActiveFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by active status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        active = request.query_params.get(\"active\", None)\n\n        if active is not None:\n            try:\n                queryset = queryset.filter(active=strtobool(active))\n            except ValueError as e:\n                raise ValidationError({\"active\": \"Invalid filter value.\"}) from e\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"active\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by active status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n\n\nclass ShiftLockedFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by locked status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        locked = request.query_params.get(\"locked\", None)\n\n        if locked is not None:\n            try:\n                queryset = queryset.filter(locked=strtobool(locked))\n            except ValueError as e:\n                raise ValidationError({\"locked\": \"Invalid filter value.\"}) from e\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"locked\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by locked status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n\n\nclass ShiftDateFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by event start/end dates.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        start, end = extract_date_range(request, allow_empty=True)\n\n        if start is not None:\n            queryset = queryset.filter(end__gte=start)\n        if end is not None:\n            queryset = queryset.filter(start__lte=end)\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"start\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter shifts by ISO date, starting with this parameter (i.e. 2021-03-30T04:20:00) where `event.end >= value`\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            },\n            {\n                \"name\": \"end\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter shifts by ISO date, ending with this parameter (i.e. 2021-05-16T13:37:00) where `event.start <= value`\",\n                \"schema\": {\n                    \"type\": \"string\",\n                },\n            },\n        ]\n", "path": "website/sales/api/v2/filters.py"}, {"content": "from rest_framework import filters\nfrom rest_framework.exceptions import ValidationError\n\nfrom utils.snippets import strtobool\n\n\nclass PublishedFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by published status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        published = request.query_params.get(\"published\", None)\n\n        if published is not None:\n            try:\n                queryset = queryset.filter(published=strtobool(published))\n            except ValueError as e:\n                raise ValidationError({\"published\": \"Invalid filter value.\"}) from e\n\n        return queryset\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"published\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by published status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n\n\nclass EventRegistrationCancelledFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by event registration cancellation status.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        cancelled = request.query_params.get(\"cancelled\", None)\n\n        if cancelled is None:\n            return queryset\n\n        try:\n            if strtobool(cancelled):\n                return queryset.exclude(date_cancelled=None)\n        except ValueError as e:\n            raise ValidationError({\"cancelled\": \"Invalid filter value.\"}) from e\n\n        return queryset.filter(date_cancelled=None)\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"cancelled\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by event registration cancellation status\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n\n\nclass EventRegistrationQueuedFilter(filters.BaseFilterBackend):\n    \"\"\"Allows you to filter by event registration by if they're in the queue.\"\"\"\n\n    def filter_queryset(self, request, queryset, view):\n        queued = request.query_params.get(\"queued\", None)\n\n        if queued is None:\n            return queryset\n\n        try:\n            if strtobool(queued):\n                return queryset.exclude(queue_position=None)\n        except ValueError as e:\n            raise ValidationError({\"queued\": \"Invalid filter value.\"}) from e\n\n        return queryset.filter(queue_position=None)\n\n    def get_schema_operation_parameters(self, view):\n        return [\n            {\n                \"name\": \"queued\",\n                \"required\": False,\n                \"in\": \"query\",\n                \"description\": \"Filter by event registration queue position\",\n                \"schema\": {\n                    \"type\": \"boolean\",\n                },\n            }\n        ]\n", "path": "website/events/api/v2/admin/filters.py"}]}