Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion openwisp_notifications/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def get_queryset(self):
return NotificationSetting.objects.exclude(
Q(organization__is_active=False)
| Q(type__in=app_settings.DISALLOW_PREFERENCES_CHANGE_TYPE)
| Q(deleted=True)
).filter(user_id=user_id)


Expand Down Expand Up @@ -223,7 +224,7 @@ def post(self, request, user_id, organization_id):
validated_data = serializer.validated_data
NotificationSetting.objects.filter(
organization_id=organization_id, user_id=user_id
).update(**validated_data)
).exclude(deleted=True).update(**validated_data)
return Response(status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Expand Down
51 changes: 51 additions & 0 deletions openwisp_notifications/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,33 @@ def test_disallowed_change_types_absent_in_notification_setting_api(self):
)
self.assertEqual(response.status_code, 404)

def test_deleted_notification_settings_absent_in_api(self):
# Retrieve an existing valid notification setting and soft-delete it
setting = self.admin.notificationsetting_set.exclude(
type__in=app_settings.DISALLOW_PREFERENCES_CHANGE_TYPE
).first()
setting.deleted = True
setting.save()

with self.subTest("deleted setting not present in list view"):
path = self._get_path("notification_setting_list")
response = self.client.get(path)
self.assertEqual(response.status_code, 200)
setting_ids = [s["id"] for s in response.data["results"]]
self.assertNotIn(str(setting.pk), setting_ids)

with self.subTest("deleted setting not accessible in detail view"):
path = self._get_path("notification_setting", setting.pk)
response = self.client.get(path)
self.assertEqual(response.status_code, 404)

with self.subTest("deleted setting absent in update view"):
path = self._get_path("notification_setting", setting.pk)
response = self.client.put(
path, data={"web": False}, content_type="application/json"
)
self.assertEqual(response.status_code, 404)

def test_notification_redirect_api(self):
def _unread_notification(notification):
notification.unread = True
Expand Down Expand Up @@ -967,6 +994,30 @@ def test_organization_notification_setting_update(self):
).exists()
)

with self.subTest("Test bulk update ignores soft-deleted settings"):
url = self._get_path("user_org_notification_setting", self.admin.pk, org.pk)

# Setup a soft-deleted setting
setting = NotificationSetting.objects.filter(
user=self.admin, organization_id=org.pk
).first()

# Record initial values
setting.web = False
setting.email = False
setting.deleted = True
setting.save()

# Perform bulk update for the organization
response = self.client.post(url, data={"web": True, "email": True})
self.assertEqual(response.status_code, 200)

# Verify the soft-deleted setting was completely ignored
setting.refresh_from_db()
self.assertFalse(setting.web)
self.assertFalse(setting.email)
self.assertTrue(setting.deleted)

@patch("openwisp_notifications.tasks.delete_ignore_object_notification.apply_async")
def test_create_ignore_obj_notification_api(self, mocked_task):
org_user = self._get_org_user()
Expand Down
Loading