diff --git a/temba/channels/migrations/0190_populate_channelevents_uuid.py b/temba/channels/migrations/0190_populate_channelevents_uuid.py new file mode 100644 index 00000000000..6d0803b6085 --- /dev/null +++ b/temba/channels/migrations/0190_populate_channelevents_uuid.py @@ -0,0 +1,39 @@ +# Generated by Django 5.1.4 on 2025-02-12 17:00 + +from django.db import migrations + +from temba.utils.uuid import uuid4 + + +def populate_channel_events_uuid(apps, schema_editor): + ChannelEvent = apps.get_model("channels", "ChannelEvent") + + num_updated = 0 + while True: + batch = list(ChannelEvent.objects.filter(uuid=None)[:100]) + if not batch: + return + + for event in batch: + event.uuid = uuid4() + event.save(update_fields=("uuid",)) + + num_updated += len(batch) + print(f"Updated {num_updated} channel events") + + +def apply_manual(): # pragma: no cover + from django.apps import apps + + populate_channel_events_uuid(apps, None) + + +class Migration(migrations.Migration): + + dependencies = [ + ("channels", "0189_channelevent_uuid_alter_channelevent_event_type"), + ] + + operations = [ + migrations.RunPython(populate_channel_events_uuid, migrations.RunPython.noop), + ] diff --git a/temba/channels/tests.py b/temba/channels/tests.py index f602afd3640..496315fb404 100644 --- a/temba/channels/tests.py +++ b/temba/channels/tests.py @@ -25,7 +25,7 @@ from temba.orgs.models import Org from temba.request_logs.models import HTTPLog from temba.templates.models import TemplateTranslation -from temba.tests import CRUDLTestMixin, MockResponse, TembaTest, matchers, mock_mailroom, override_brand +from temba.tests import CRUDLTestMixin, MigrationTest, MockResponse, TembaTest, matchers, mock_mailroom, override_brand from temba.tests.crudl import StaffRedirect from temba.triggers.models import Trigger from temba.utils import json @@ -2126,3 +2126,25 @@ def test_courier_urls(self): response = self.client.get(reverse("courier.t", args=[self.channel.uuid, "receive"])) self.assertEqual(response.status_code, 404) self.assertEqual(response.content, b"this URL should be mapped to a Courier instance") + + +class TestPopulateChannelEventUUID(MigrationTest): + app = "channels" + migrate_from = "0189_channelevent_uuid_alter_channelevent_event_type" + migrate_to = "0190_populate_channelevents_uuid" + + def setUpBeforeMigration(self, apps): + contact = self.create_contact("Joe", phone="+250788111222") + self.evt = ChannelEvent.objects.create( + org=self.org, + channel=self.channel, + event_type=ChannelEvent.TYPE_STOP_CONTACT, + contact=contact, + created_on=timezone.now() - timedelta(days=1), + occurred_on=timezone.now() - timedelta(days=1), + ) + self.assertIsNone(self.evt.uuid) + + def test_migration(self): + self.evt.refresh_from_db() + self.assertIsNotNone(self.evt.uuid)