Skip to content

Commit 7a5a032

Browse files
committed
Ensure bot/infractions does not accept both expires and permanent filters
Expires and permanent=false are permitted and tested for. Expires_before also filters the database for permanent=false explicitly
1 parent 45dfba5 commit 7a5a032

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

pydis_site/apps/api/tests/test_infractions.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,35 @@ def test_after_after_before_invalid(self):
204204
self.assertIn("expires_before", errors)
205205
self.assertIn("expires_after", errors)
206206

207+
def test_permanent_after_invalid(self):
208+
url = reverse('bot:infraction-list', host='api')
209+
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
210+
response = self.client.get(f'{url}?permanent=true&expires_after={target_time.isoformat()}')
211+
212+
self.assertEqual(response.status_code, 400)
213+
errors = list(response.json())
214+
self.assertEqual("permanent", errors[0])
215+
216+
def test_permanent_before_invalid(self):
217+
url = reverse('bot:infraction-list', host='api')
218+
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
219+
response = self.client.get(f'{url}?permanent=true&expires_before={target_time.isoformat()}')
220+
221+
self.assertEqual(response.status_code, 400)
222+
errors = list(response.json())
223+
self.assertEqual("permanent", errors[0])
224+
225+
def test_nonpermanent_before(self):
226+
url = reverse('bot:infraction-list', host='api')
227+
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=6)
228+
response = self.client.get(
229+
f'{url}?permanent=false&expires_before={target_time.isoformat()}'
230+
)
231+
232+
self.assertEqual(response.status_code, 200)
233+
self.assertEqual(len(response.json()), 1)
234+
self.assertEqual(response.json()[0]["id"], self.superstar_expires_soon.id)
235+
207236
def test_filter_manytypes(self):
208237
url = reverse('bot:infraction-list', host='api')
209238
response = self.client.get(f'{url}?types=mute,ban')

pydis_site/apps/api/viewsets/bot/infraction.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class InfractionViewSet(
5656
Invalid query parameters are ignored.
5757
Only one of `type` and `types` may be provided. If both `expires_before` and `expires_after`
5858
are provided, `expires_after` must come after `expires_before`.
59+
If `permanent` is provided and true, `expires_before` and `expires_after` must not be provided.
5960
6061
#### Response format
6162
Response is paginated but the result is returned without any pagination metadata.
@@ -201,6 +202,23 @@ def get_queryset(self) -> QuerySet:
201202
'expires_after': ['cannot be before expires_before'],
202203
})
203204

205+
if (
206+
('expires_at__lte' in additional_filters or 'expires_at__gte' in additional_filters)
207+
and 'expires_at__isnull' in additional_filters
208+
and additional_filters['expires_at__isnull']
209+
):
210+
raise ValidationError({
211+
'permanent': [
212+
'cannot filter for permanent infractions at the'
213+
' same time as expires_at or expires_before',
214+
]
215+
})
216+
217+
if filter_expires_before:
218+
# Filter out permanent infractions specifically if we want ones that will expire
219+
# before a given date
220+
additional_filters['expires_at__isnull'] = False
221+
204222
filter_types = self.request.query_params.get('types')
205223
if filter_types:
206224
if self.request.query_params.get('type'):

0 commit comments

Comments
 (0)