Skip to content

Commit

Permalink
Make email and mailing_list jointly unique
Browse files Browse the repository at this point in the history
  • Loading branch information
juuso-j committed Apr 30, 2024
1 parent 59fc260 commit 128c63c
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 6 deletions.
13 changes: 9 additions & 4 deletions account/api/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django import db
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.db.utils import IntegrityError
from drf_spectacular.utils import extend_schema, OpenApiResponse
from rest_framework import status, viewsets
from rest_framework.decorators import action
Expand Down Expand Up @@ -93,8 +94,7 @@ def subscribe(self, request):
email = request.data.get("email", None)
if not email:
return Response("No 'email' provided", status=status.HTTP_400_BAD_REQUEST)
if MailingListEmail.objects.filter(email=email).count() > 0:
return Response("'email' exists", status=status.HTTP_400_BAD_REQUEST)

try:
validate_email(email)
except ValidationError as e:
Expand All @@ -103,8 +103,13 @@ def subscribe(self, request):
if not mailing_list:
# In case mailing list is not created for the result, it is created.
mailing_list = MailingList.objects.create(result=result)

MailingListEmail.objects.create(mailing_list=mailing_list, email=email)
try:
MailingListEmail.objects.create(mailing_list=mailing_list, email=email)
except IntegrityError:
return Response(
"'email' and 'result' must be jointly null",
status=status.HTTP_400_BAD_REQUEST,
)
user.has_subscribed = True
user.save()
return Response("subscribed", status=status.HTTP_201_CREATED)
Expand Down
25 changes: 25 additions & 0 deletions account/migrations/0015_email_and_mailing_list_jointly_unique.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.1.13 on 2024-04-30 07:25

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("account", "0014_remove_profile_is_filled_for_fun"),
]

operations = [
migrations.AlterField(
model_name="mailinglistemail",
name="email",
field=models.EmailField(max_length=254),
),
migrations.AddConstraint(
model_name="mailinglistemail",
constraint=models.UniqueConstraint(
fields=("email", "mailing_list"),
name="email_and_mailing_list_must_be_jointly:unique",
),
),
]
12 changes: 10 additions & 2 deletions account/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,18 @@ def csv_emails(self):


class MailingListEmail(models.Model):
email = models.EmailField(unique=True)
email = models.EmailField()
mailing_list = models.ForeignKey(
MailingList, related_name="emails", on_delete=models.CASCADE
)

def __str__(self):
return self.email
return f"{self.email} {self.mailing_list}"

class Meta:
constraints = [
models.UniqueConstraint(
fields=["email", "mailing_list"],
name="email_and_mailing_list_must_be_jointly:unique",
)
]
31 changes: 31 additions & 0 deletions account/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,34 @@ def test_mailing_list_unsubscribe_email_not_provided(
url = reverse("account:profiles-unsubscribe")
response = api_client_with_custom_ip_address.post(url)
assert response.status_code == 400


@pytest.mark.django_db
@pytest.mark.parametrize(
"ip_address",
[
("100.19.91.40"),
],
)
def test_mailing_list_unique_constraints(api_client_with_custom_ip_address, users):
url = reverse("account:profiles-subscribe")
user = users.get(username="test1")
response = api_client_with_custom_ip_address.post(
url, {"email": "[email protected]", "user": user.id}
)
assert response.status_code == 201
assert MailingListEmail.objects.count() == 1
# Subscribed as the result (MailingList) is different than for user 'test1'
user = users.get(username="test2")
response = api_client_with_custom_ip_address.post(
url, {"email": "[email protected]", "user": user.id}
)
assert response.status_code == 201
assert MailingListEmail.objects.count() == 2
# Fails, as the email and result are not jointly unique.
user = users.get(username="test3")
response = api_client_with_custom_ip_address.post(
url, {"email": "[email protected]", "user": user.id}
)
assert response.status_code == 400
assert MailingListEmail.objects.count() == 2

0 comments on commit 128c63c

Please sign in to comment.