mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	This commit removes the 'email_token' field from the 'Stream' model, introduces a new model 'ChannelEmailAddress', and backfills it. This is a prep work towards our plan to generate unique channel emails for different users, which can be used to check post permissions at message send time.
		
			
				
	
	
		
			126 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Generated by Django 5.0.9 on 2024-11-21 12:58
 | 
						|
 | 
						|
import django.db.models.deletion
 | 
						|
import django.utils.timezone
 | 
						|
from django.conf import settings
 | 
						|
from django.db import connection, migrations, models
 | 
						|
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
 | 
						|
from django.db.migrations.state import StateApps
 | 
						|
from psycopg2.sql import SQL
 | 
						|
 | 
						|
from zerver.models.streams import generate_email_token_for_stream
 | 
						|
 | 
						|
 | 
						|
def backfill_channelemailaddress(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None:
 | 
						|
    UserProfile = apps.get_model("zerver", "UserProfile")
 | 
						|
 | 
						|
    with connection.cursor() as cursor:
 | 
						|
        cursor.execute(SQL("SELECT MAX(id) FROM zerver_stream;"))
 | 
						|
        (max_id,) = cursor.fetchone()
 | 
						|
 | 
						|
    if max_id is None:
 | 
						|
        return
 | 
						|
 | 
						|
    BATCH_SIZE = 10000
 | 
						|
    max_id += BATCH_SIZE / 2
 | 
						|
    lower_id_bound = 0
 | 
						|
    mail_gateway_bot_id = UserProfile.objects.get(email__iexact=settings.EMAIL_GATEWAY_BOT).id
 | 
						|
    while lower_id_bound < max_id:
 | 
						|
        upper_id_bound = min(lower_id_bound + BATCH_SIZE, max_id)
 | 
						|
        with connection.cursor() as cursor:
 | 
						|
            query = SQL("""
 | 
						|
                INSERT INTO zerver_channelemailaddress (realm_id, channel_id, creator_id, sender_id, email_token, date_created, deactivated)
 | 
						|
                SELECT realm_id, id, creator_id, %(mail_gateway_bot_id)s, email_token, date_created, deactivated
 | 
						|
                FROM zerver_stream
 | 
						|
                WHERE id > %(lower_id_bound)s AND id <= %(upper_id_bound)s;
 | 
						|
                """)
 | 
						|
            cursor.execute(
 | 
						|
                query,
 | 
						|
                {
 | 
						|
                    "mail_gateway_bot_id": mail_gateway_bot_id,
 | 
						|
                    "lower_id_bound": lower_id_bound,
 | 
						|
                    "upper_id_bound": upper_id_bound,
 | 
						|
                },
 | 
						|
            )
 | 
						|
 | 
						|
        print(f"Processed {upper_id_bound} / {max_id}")
 | 
						|
        lower_id_bound += BATCH_SIZE
 | 
						|
 | 
						|
 | 
						|
class Migration(migrations.Migration):
 | 
						|
    atomic = False
 | 
						|
 | 
						|
    dependencies = [
 | 
						|
        ("zerver", "0628_remove_realm_invite_to_realm_policy"),
 | 
						|
    ]
 | 
						|
 | 
						|
    operations = [
 | 
						|
        migrations.CreateModel(
 | 
						|
            name="ChannelEmailAddress",
 | 
						|
            fields=[
 | 
						|
                (
 | 
						|
                    "id",
 | 
						|
                    models.BigAutoField(
 | 
						|
                        auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
                (
 | 
						|
                    "email_token",
 | 
						|
                    models.CharField(
 | 
						|
                        db_index=True,
 | 
						|
                        default=generate_email_token_for_stream,
 | 
						|
                        max_length=32,
 | 
						|
                        unique=True,
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
                ("date_created", models.DateTimeField(default=django.utils.timezone.now)),
 | 
						|
                ("deactivated", models.BooleanField(default=False)),
 | 
						|
                (
 | 
						|
                    "channel",
 | 
						|
                    models.ForeignKey(
 | 
						|
                        on_delete=django.db.models.deletion.CASCADE, to="zerver.stream"
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
                (
 | 
						|
                    "creator",
 | 
						|
                    models.ForeignKey(
 | 
						|
                        null=True,
 | 
						|
                        on_delete=django.db.models.deletion.CASCADE,
 | 
						|
                        related_name="+",
 | 
						|
                        to=settings.AUTH_USER_MODEL,
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
                (
 | 
						|
                    "realm",
 | 
						|
                    models.ForeignKey(
 | 
						|
                        on_delete=django.db.models.deletion.CASCADE, to="zerver.realm"
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
                (
 | 
						|
                    "sender",
 | 
						|
                    models.ForeignKey(
 | 
						|
                        on_delete=django.db.models.deletion.CASCADE,
 | 
						|
                        related_name="+",
 | 
						|
                        to=settings.AUTH_USER_MODEL,
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
            ],
 | 
						|
            options={
 | 
						|
                "indexes": [
 | 
						|
                    models.Index(
 | 
						|
                        fields=["realm", "channel"],
 | 
						|
                        name="zerver_channelemailaddress_realm_id_channel_id_idx",
 | 
						|
                    )
 | 
						|
                ],
 | 
						|
                "unique_together": {("channel", "creator", "sender")},
 | 
						|
            },
 | 
						|
        ),
 | 
						|
        migrations.RunPython(
 | 
						|
            backfill_channelemailaddress, reverse_code=migrations.RunPython.noop, elidable=True
 | 
						|
        ),
 | 
						|
        migrations.RemoveField(
 | 
						|
            model_name="stream",
 | 
						|
            name="email_token",
 | 
						|
        ),
 | 
						|
    ]
 |