Skip to content

Commit

Permalink
Allow duplicate email addresses
Browse files Browse the repository at this point in the history
Unique constraint are dropped from account_emailaddress table because it's already previously added in the account migrations. Instead add unique together constraint for email and user_id fields. See 0002_email_max_length.py migration in allauth/account.

ALTER TABLE account_emailaddress DROP CONSTRAINT account_emailaddress_email_key;
ALTER TABLE account_emailaddress ADD CONSTRAINT account_emailaddress_email_key UNIQUE (user_id, email);
  • Loading branch information
jorilindell committed Sep 23, 2024
1 parent 5e8e4a0 commit f8d2995
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 1 deletion.
1 change: 1 addition & 0 deletions respa/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ def get_git_revision_hash():

SOCIALACCOUNT_PROVIDERS = {"tampere": {"VERIFIED_EMAIL": True}}
LOGIN_REDIRECT_URL = "/"
ACCOUNT_UNIQUE_EMAIL = False
ACCOUNT_LOGOUT_ON_GET = True
SOCIALACCOUNT_ADAPTER = "tamusers.adapter.SocialAccountAdapter"

Expand Down
3 changes: 2 additions & 1 deletion users/api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from allauth.socialaccount.models import EmailAddress
from django.conf import settings
from django.contrib.auth import get_user_model
from rest_framework import permissions, serializers, generics, viewsets, status
from rest_framework.decorators import action
Expand Down Expand Up @@ -97,7 +98,7 @@ def set_email(self, request, pk=None):
status=status.HTTP_400_BAD_REQUEST
)

if EmailAddress.objects.filter(email=email):
if settings.ACCOUNT_UNIQUE_EMAIL and EmailAddress.objects.filter(email=email):
return Response(
{"detail": "The email address is already in use."},
status=status.HTTP_400_BAD_REQUEST
Expand Down
37 changes: 37 additions & 0 deletions users/migrations/0012_allow_duplicate_account_emailaddresses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from django.db import migrations

class Migration(migrations.Migration):

dependencies = [
('account', '0002_email_max_length'),
('users', '0011_change_last_name_length'),
]

operations = [
migrations.RunSQL(
sql=[
"""
DO $$
DECLARE
r RECORD;
BEGIN
FOR r IN
SELECT conname
FROM pg_constraint
JOIN pg_class ON conrelid = pg_class.oid
WHERE pg_class.relname = 'account_emailaddress'
AND conname LIKE '%email%'
AND contype = 'u'
LOOP
EXECUTE 'ALTER TABLE account_emailaddress DROP CONSTRAINT ' || r.conname;
END LOOP;
END $$;
""",
"ALTER TABLE account_emailaddress ADD CONSTRAINT account_emailaddress_email_key UNIQUE (user_id, email);",
],
reverse_sql=[
"ALTER TABLE account_emailaddress DROP CONSTRAINT account_emailaddress_email_key;",
"ALTER TABLE account_emailaddress ADD CONSTRAINT account_emailaddress_email_key UNIQUE (email);",
],
),
]
15 changes: 15 additions & 0 deletions users/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from allauth.account.models import EmailAddress
from django.conf import settings
from django.contrib.auth import get_user_model
from django.urls import reverse
from rest_framework import status
Expand Down Expand Up @@ -64,6 +65,7 @@ def test_set_email_not_provided(self):
self.assertEqual(self.user.email, "")

def test_set_email_already_in_use(self):
settings.ACCOUNT_UNIQUE_EMAIL = True
url = reverse("user-set-email", kwargs={"pk": self.user.pk})
data = {"email": "[email protected]"} # Email already used by other_user

Expand All @@ -74,3 +76,16 @@ def test_set_email_already_in_use(self):
response.data, {"detail": "The email address is already in use."}
)
self.assertEqual(self.user.email, "")

def test_allow_to_set_duplicate_email(self):
settings.ACCOUNT_UNIQUE_EMAIL = False
url = reverse("user-set-email", kwargs={"pk": self.user.pk})
data = {"email": "[email protected]"} # Email already used by other_user

response = self.client.post(url, data, format="json")

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data, {"detail": "Email set successfully."}
)
self.assertEqual(self.user.email, "[email protected]")

0 comments on commit f8d2995

Please sign in to comment.