Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TTVA-199 | Allow duplicate email addresses #181

Merged

Conversation

jorilindell
Copy link
Collaborator

@jorilindell jorilindell commented Sep 20, 2024

Description

Add ACCOUNT_UNIQUE_EMAIL = False environment variable and logic to allow duplicate email addresses if ACCOUNT_UNIQUE_EMAIL is False

Unique constraint is dropped from account_emailaddress table manually because it's already added in the allauth/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);

@jorilindell jorilindell force-pushed the TTVA-199-allow-duplicate-email-addresses branch from 2ade16d to 5ed4c01 Compare September 23, 2024 10:35
@@ -0,0 +1,21 @@
from django.db import migrations

class Migration(migrations.Migration):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check if the constraint exists before trying to remove it. Would something like this work:

from django.db import migrations, models
from django.db.utils import OperationalError

def check_constraint_exists(apps, schema_editor):
    # Get the connection to the database
    connection = schema_editor.connection

    constraint_name = 'account_emailaddress_email_key'
    table_name = 'account_emailaddress'

    # Check if the constraint exists
    sql = f"""
    SELECT conname
    FROM pg_constraint
    WHERE conname = '{constraint_name}' AND conrelid = '{table_name}'::regclass;
    """

    with connection.cursor() as cursor:
        cursor.execute(sql)
        result = cursor.fetchone()
        return result is not None

def modify_constraints(apps, schema_editor):
    if check_constraint_exists(apps, schema_editor):
        # Remove the existing unique constraint on 'email'
        schema_editor.remove_constraint(
            model_name='emailaddress',
            name='account_emailaddress_email_key',
        )
    
    # Add the new unique constraint on ('user', 'email')
    schema_editor.add_constraint(
        model_name='emailaddress',
        constraint=models.UniqueConstraint(
            fields=['user', 'email'],
            name='account_emailaddress_email_key',
        ),
    )

class Migration(migrations.Migration):

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

    operations = [
        migrations.RunPython(modify_constraints),
    ]

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking something like this:

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);",
            ],
        ),
    ]

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);
@jorilindell jorilindell force-pushed the TTVA-199-allow-duplicate-email-addresses branch from 5ed4c01 to f8d2995 Compare September 23, 2024 12:16
Copy link
Collaborator

@jopesy jopesy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@jorilindell jorilindell merged commit dc5092d into tre-varaamo-qa Sep 23, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants