From 624a78eb559f8ab9fa91d45aa3e87a7b4fddf5cc Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Sat, 28 Dec 2024 16:53:16 +0100 Subject: [PATCH] Implement support for whatsapp in SecretSanta --- eas/api/serializers.py | 10 +++- eas/api/tests/int/test_secret_santa.py | 80 +++++++++++++++++++++++++- eas/api/views.py | 29 ++++++++-- swagger.yaml | 6 +- 4 files changed, 115 insertions(+), 10 deletions(-) diff --git a/eas/api/serializers.py b/eas/api/serializers.py index fb9d382..7015967 100644 --- a/eas/api/serializers.py +++ b/eas/api/serializers.py @@ -261,11 +261,19 @@ class Meta: class SecretSantaParticipantSerializer(serializers.Serializer): name = serializers.CharField(max_length=100) - email = serializers.EmailField(max_length=100) + email = serializers.EmailField(max_length=100, required=False) + phone_number = serializers.RegexField( + regex=r"^\+\d{1,3}\d{4,14}$", max_length=100, required=False + ) exclusions = serializers.ListField( child=serializers.CharField(max_length=100), max_length=500, required=False ) + def validate(self, data): # pylint: disable=arguments-differ + if not data.get("email") and not data.get("phone_number"): + raise serializers.ValidationError("phone_or_email_required") + return data + class SecretSantaSerializer(serializers.Serializer): participants = serializers.ListField( diff --git a/eas/api/tests/int/test_secret_santa.py b/eas/api/tests/int/test_secret_santa.py index b36d403..7d0a8ff 100644 --- a/eas/api/tests/int/test_secret_santa.py +++ b/eas/api/tests/int/test_secret_santa.py @@ -20,7 +20,7 @@ def setUp(self): "participants": [ {"name": "First Name", "email": "email@address1.com"}, {"name": "Second Name", "email": "email@address2.com"}, - {"name": "Third Name", "email": "email@address2.com"}, + {"name": "Third Name", "phone_number": "+34123456789"}, ], } boto_patcher = mock.patch("eas.api.amazonsqs.boto3") @@ -33,6 +33,9 @@ def test_create_secret_santa(self): response.status_code, status.HTTP_201_CREATED, response.content ) assert response.json() == {"id": mock.ANY} + assert self.sqs.send_message.call_count == 1 + assert "email@address1.com" in self.sqs.send_message.call_args[1]["MessageBody"] + assert "+34123456789" in self.sqs.send_message.call_args[1]["MessageBody"] def test_create_with_exclusions(self): self.secret_santa_data = { @@ -110,8 +113,8 @@ def test_retrieve(self): self.assertEqual(response.data, {"source": "From name", "target": "To Name"}) def test_missing_fields(self): - secret_santa_data = {} - response = self.client.post(self.list_url, secret_santa_data) + self.secret_santa_data = {} + response = self.client.post(self.list_url, self.secret_santa_data) self.assertEqual( response.status_code, status.HTTP_400_BAD_REQUEST, response.content ) @@ -126,6 +129,39 @@ def test_missing_fields(self): } } + def test_missing_target_create(self): + self.secret_santa_data = { + "language": "en", + "participants": [ + { + "name": "First Name", + }, + { + "name": "Second Name", + "email": "email@address2.com", + }, + { + "name": "Third Name", + "email": "email@address2.com", + }, + ], + } + response = self.client.post(self.list_url, self.secret_santa_data) + self.assertEqual( + response.status_code, status.HTTP_400_BAD_REQUEST, response.content + ) + assert response.json() == { + "schema": { + "participants": { + "0": { + "non_field_errors": [ + {"code": "invalid", "message": "phone_or_email_required"} + ] + } + } + } + } + def test_fecth_secret_santa_admin(self): # Create draw response = self.client.post(self.list_url, self.secret_santa_data) @@ -191,6 +227,44 @@ def test_resend_email_success(self): self.assertEqual(response.status_code, status.HTTP_200_OK, response.content) assert self.sqs.send_message.call_count == 1 + def test_resend_whatsapp_success(self): + draw = models.SecretSanta() + draw.save() + result = models.SecretSantaResult( + source="From name", target="To Name", draw=draw + ) + result.save() + assert self.sqs.send_message.call_count == 0 + + url = reverse( + "secret-santa-resend-email", + kwargs=dict(draw_pk=draw.id, result_pk=result.id), + ) + with freezegun.freeze_time(NOW + dt.timedelta(days=1)): + response = self.client.post( + url, {"language": "en", "phone_number": "+34123456789"} + ) + self.assertEqual(response.status_code, status.HTTP_200_OK, response.content) + assert self.sqs.send_message.call_count == 1 + + def test_resend_missing_target(self): + draw = models.SecretSanta() + draw.save() + result = models.SecretSantaResult( + source="From name", target="To Name", draw=draw + ) + result.save() + assert self.sqs.send_message.call_count == 0 + + url = reverse( + "secret-santa-resend-email", + kwargs=dict(draw_pk=draw.id, result_pk=result.id), + ) + with freezegun.freeze_time(NOW + dt.timedelta(days=1)): + response = self.client.post(url, {"language": "en"}) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + assert self.sqs.send_message.call_count == 0 + def test_resend_email_unlinked_result_fails(self): draw = models.SecretSanta() draw.save() diff --git a/eas/api/views.py b/eas/api/views.py index e6c0f20..d32c188 100644 --- a/eas/api/views.py +++ b/eas/api/views.py @@ -226,7 +226,14 @@ def create(self, request, *args, **kwargs): serializer = serializers.SecretSantaSerializer(data=request.data) serializer.is_valid(raise_exception=True) data = serializer.validated_data - emails_map = {p["name"]: p["email"] for p in data["participants"]} + emails_map = { + p["name"]: p["email"] for p in data["participants"] if p.get("email") + } + phones_map = { + p["name"]: p["phone_number"] + for p in data["participants"] + if p.get("phone_number") + } exclusions_map = { p["name"]: set(p.get("exclusions") or []) for p in data["participants"] } @@ -244,15 +251,21 @@ def create(self, request, *args, **kwargs): draw = models.SecretSanta() draw.save() emails = [] + phones = [] for source, target in results: result = models.SecretSantaResult(source=source, target=target, draw=draw) result.save() - target = emails_map[source] - emails.append((target, result.id)) + if source in emails_map: + target = emails_map[source] + emails.append((target, result.id)) + else: + target = phones_map[source] + phones.append((target, result.id)) amazonsqs.send_secret_santa_message( { "lang": data["language"], "mails": emails, + "phones": phones, "draw_id": draw.id, "admin_email": data.get("admin_email"), } @@ -339,10 +352,18 @@ def secret_santa_resend_email(request, draw_pk, result_pk): result.draw = None result.save() + payload = { + "lang": request.data["language"], + } + if "email" in request.data: + payload["mails"] = [(request.data["email"], new_result.id)] + elif "phone_number" in request.data: + payload["phones"] = [(request.data["phone_number"], new_result.id)] + else: + raise ValidationError("email or phone_number missing") from None amazonsqs.send_secret_santa_message( { "lang": request.data["language"], - "mails": [(request.data["email"], new_result.id)], } ) LOG.info("Returning result %s", new_result) diff --git a/swagger.yaml b/swagger.yaml index 14c9bb0..41f1cce 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -1566,13 +1566,14 @@ components: type: object required: - name - - email - exclusions properties: name: type: string email: type: string + phone_number: + type: string exclusions: type: array items: @@ -1626,7 +1627,6 @@ components: type: object required: - language - - email properties: language: type: string @@ -1635,6 +1635,8 @@ components: - en email: type: string + phone_number: + type: string SecretSantaResendEmailResponse: type: object properties: