diff --git a/lego/apps/email/serializers.py b/lego/apps/email/serializers.py index 97ef9df2f..e5209b771 100644 --- a/lego/apps/email/serializers.py +++ b/lego/apps/email/serializers.py @@ -1,3 +1,5 @@ +from typing import Any + from django.core.exceptions import ValidationError from rest_framework import exceptions, serializers @@ -7,7 +9,7 @@ PublicUserListField, PublicUserWithGroupsField, ) -from lego.apps.users.models import User +from lego.apps.users.models import Membership, User from .fields import EmailAddressField @@ -44,6 +46,33 @@ class Meta: "additional_emails", ) + def validate(self, attrs: Any) -> Any: + # Use existing values where missing to support patch requests + get = ( + lambda index: attrs[index] + if index in attrs + else getattr(self.instance, index) + ) + length = ( + lambda value: len(value) if hasattr(value, "__len__") else value.count() + ) + # Require at least one receiver of the email list + users_len, emails_len = length(get("users")), length(get("additional_emails")) + if users_len == 0 and emails_len == 0: + groups = ( + attrs["groups"] if "groups" in attrs else self.instance.groups.all() + ) + group_roles = get("group_roles") + memberships = Membership.objects.filter(abakus_group__in=groups) + + if length(group_roles) > 0: + memberships = memberships.filter(role__in=group_roles) + + if not memberships.exists(): + raise ValidationError("Cannot create a mail list without receivers") + + return super().validate(attrs) + class EmailListDetailSerializer(EmailListSerializer): users = PublicUserListField({"read_only": True}) diff --git a/lego/apps/email/tests/test_views.py b/lego/apps/email/tests/test_views.py index 61562740d..5405a248e 100644 --- a/lego/apps/email/tests/test_views.py +++ b/lego/apps/email/tests/test_views.py @@ -116,6 +116,21 @@ def test_create_list_invalid_additional_email(self): ) self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code) + def test_create_list_no_recipients(self): + """Bad request when user tries to create list with no recipients""" + response = self.client.post( + self.url, + { + "name": "Webkom", + "email": "webbers", + "users": [], + "groups": [self.admin_group.id], + "group_roles": ["recruiting"], + "additional_emails": [], + }, + ) + self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code) + def test_edit_additional_email(self): """Test ability to remove an additional email""" response = self.client.patch( @@ -138,7 +153,9 @@ def test_edit_additional_email(self): def test_delete_additional_email(self): """Test ability to set additional emails to an empty array""" - response = self.client.patch(f"{self.url}1/", {"additional_emails": []}) + response = self.client.patch( + f"{self.url}1/", {"additional_emails": [], "users": [1]} + ) self.assertEqual(status.HTTP_200_OK, response.status_code) self.assertEqual([], EmailList.objects.get(id=1).additional_emails) @@ -149,6 +166,29 @@ def test_change_assigned_email(self): self.assertEqual("address", EmailList.objects.get(id=1).email_id) + def test_edit_list_no_recipients(self): + """Bad request when user tries to edit list with no recipients""" + response = self.client.patch( + f"{self.url}1/", + { + "users": [], + "groups": [self.admin_group.id], + "group_roles": ["recruiting"], + "additional_emails": [], + }, + ) + self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code) + + def test_edit_list_no_recipients_partial(self): + """Bad request when user tries to edit list with no recipients""" + response = self.client.patch( + f"{self.url}1/", + { + "additional_emails": [], + }, + ) + self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code) + def test_delete_endpoint_not_available(self): """The delete endpoint is'nt available.""" response = self.client.delete(f"{self.url}1/")