From 0597f6b57378f368f8c26b104a20add81aee7177 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 31 Jul 2025 10:54:31 +0200 Subject: [PATCH 1/2] Changed HTTP method for alarm bulk delete endpoint DELETE -> POST --- frontend/src/api/alarms.js | 4 +--- modoboa/admin/api/v2/serializers.py | 5 +++++ modoboa/admin/api/v2/tests.py | 8 +++++--- modoboa/admin/api/v2/viewsets.py | 22 ++++++++++++---------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/frontend/src/api/alarms.js b/frontend/src/api/alarms.js index a25b368ef..2c9043cf2 100644 --- a/frontend/src/api/alarms.js +++ b/frontend/src/api/alarms.js @@ -13,8 +13,6 @@ export default { return repository.delete(`${resource}/${alarmId}/`) }, bulkDelete(alarmsIds) { - return repository.delete(`${resource}/bulk_delete/`, { - params: { ids: alarmsIds }, - }) + return repository.post(`${resource}/bulk_delete/`, { ids: alarmsIds }) }, } diff --git a/modoboa/admin/api/v2/serializers.py b/modoboa/admin/api/v2/serializers.py index b955685e0..f41e729d8 100644 --- a/modoboa/admin/api/v2/serializers.py +++ b/modoboa/admin/api/v2/serializers.py @@ -741,6 +741,11 @@ class AlarmSerializer(serializers.ModelSerializer): model = models.Alarm +class AlarmBulkDeleteSerializer(serializers.Serializer): + + ids = serializers.ListField(child=serializers.IntegerField()) + + class AlarmSwitchStatusSerializer(serializers.Serializer): """Serializer to switch the status of an Alarm.""" diff --git a/modoboa/admin/api/v2/tests.py b/modoboa/admin/api/v2/tests.py index f495c0ebb..baebf5001 100644 --- a/modoboa/admin/api/v2/tests.py +++ b/modoboa/admin/api/v2/tests.py @@ -806,9 +806,10 @@ class AlarmViewSetTestCase(ModoAPITestCase): def test_bulk_delete(self): url = reverse("v2:alarm-bulk-delete") - resp = self.client.delete(url) + resp = self.client.post(url) self.assertEqual(resp.status_code, 400) - resp = self.client.delete(f"{url}?ids[]=toto") + data = {"ids": ["toto"]} + resp = self.client.post(url, data, format="json") self.assertEqual(resp.status_code, 400) alarm1 = factories.AlarmFactory( domain__name="test.com", mailbox=None, title="Test alarm" @@ -816,7 +817,8 @@ class AlarmViewSetTestCase(ModoAPITestCase): alarm2 = factories.AlarmFactory( domain__name="test.com", mailbox=None, title="Test alarm" ) - resp = self.client.delete(f"{url}?ids[]={alarm1.pk}&ids[]={alarm2.pk}") + data = {"ids": [alarm1.pk, alarm2.pk]} + resp = self.client.delete(url, data, format="json") self.assertEqual(resp.status_code, 204) with self.assertRaises(models.Alarm.DoesNotExist): alarm1.refresh_from_db() diff --git a/modoboa/admin/api/v2/viewsets.py b/modoboa/admin/api/v2/viewsets.py index 702440aa9..e75d137c4 100644 --- a/modoboa/admin/api/v2/viewsets.py +++ b/modoboa/admin/api/v2/viewsets.py @@ -387,11 +387,18 @@ class AlarmViewSet( .order_by("-created") ) + def get_serializer_class(self, *args, **kwargs): + if self.action == "bulk_delete": + return serializers.AlarmBulkDeleteSerializer + elif self.action == "switch": + return serializers.AlarmSwitchStatusSerializer + return serializers.AlarmSerializer + @action(methods=["patch"], detail=True) def switch(self, request, **kwargs): """Custom update method that switch status of an alarm.""" alarm = self.get_object() - serializer = serializers.AlarmSwitchStatusSerializer(data=request.data) + serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) if serializer.data["status"] == constants.ALARM_CLOSED: alarm.close() @@ -399,15 +406,10 @@ class AlarmViewSet( alarm.reopen() return response.Response(status=status.HTTP_204_NO_CONTENT) - @action(methods=["delete"], detail=False) + @action(methods=["post"], detail=False) def bulk_delete(self, request, **kwargs): """Delete multiple alarms at the same time.""" - ids = request.query_params.getlist("ids[]") - if not ids: - return response.Response(_("No alarm ID provided"), status=400) - try: - ids = [int(alarm_id) for alarm_id in ids] - except ValueError: - return response.Response(_("Received invalid alarm id(s)"), status=400) - models.Alarm.objects.filter(pk__in=ids).delete() + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + models.Alarm.objects.filter(pk__in=serializer.validated_data["ids"]).delete() return response.Response(status=204) From efbb7e5cb90dfb16c914fdf37bf1728871c11c99 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 31 Jul 2025 11:08:53 +0200 Subject: [PATCH 2/2] Replaced wrong method name --- modoboa/admin/api/v2/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modoboa/admin/api/v2/tests.py b/modoboa/admin/api/v2/tests.py index baebf5001..f5d318d0b 100644 --- a/modoboa/admin/api/v2/tests.py +++ b/modoboa/admin/api/v2/tests.py @@ -818,7 +818,7 @@ class AlarmViewSetTestCase(ModoAPITestCase): domain__name="test.com", mailbox=None, title="Test alarm" ) data = {"ids": [alarm1.pk, alarm2.pk]} - resp = self.client.delete(url, data, format="json") + resp = self.client.post(url, data, format="json") self.assertEqual(resp.status_code, 204) with self.assertRaises(models.Alarm.DoesNotExist): alarm1.refresh_from_db()