From 815cece961ae1662d0d1740d188bdc66af413831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20L=C3=A9ger?= Date: Wed, 18 Dec 2024 17:14:50 -0500 Subject: [PATCH] fix(projectOwnershipTransfer): ensure the path of OpenRosa media files is correct for transferred projects TASK-1352 (#5385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### 📣 Summary Extended the bug fix from #5365 to address issues in existing projects. ### 📖 Description This update addresses the issue where OpenRosa media file paths were not updated correctly during project ownership transfers for existing projects. This misalignment led to 404 errors when users attempted to access transferred projects in Collect due to missing media files. ### Notes The fix leverages the new long-running migration flow to address the issue in the background. --- ...ect_ownership_transfer_with_media_files.py | 56 +++++++++++++++++++ ...ect_ownership_transfer_with_media_files.py | 25 +++++++++ 2 files changed, 81 insertions(+) create mode 100644 kobo/apps/long_running_migrations/jobs/0002_fix_project_ownership_transfer_with_media_files.py create mode 100644 kobo/apps/long_running_migrations/migrations/0002_fix_failed_project_ownership_transfer_with_media_files.py diff --git a/kobo/apps/long_running_migrations/jobs/0002_fix_project_ownership_transfer_with_media_files.py b/kobo/apps/long_running_migrations/jobs/0002_fix_project_ownership_transfer_with_media_files.py new file mode 100644 index 0000000000..fd627e7b2e --- /dev/null +++ b/kobo/apps/long_running_migrations/jobs/0002_fix_project_ownership_transfer_with_media_files.py @@ -0,0 +1,56 @@ +# Generated on 2024-12-18 +from django.db.models import Q, OuterRef, Subquery + +from kobo.apps.openrosa.apps.logger.models import XForm +from kobo.apps.openrosa.apps.main.models import MetaData +from kpi.models.asset import Asset +from kpi.models.asset_file import AssetFile +from kobo.apps.project_ownership.models import Transfer + + +def run(): + """ + Update OpenRosa MetaData objects that were not updated when project + ownership was transferred to someone else. This fixes a bug introduced + and later addressed in KPI (issue #5365). + """ + + # Step 1: Retrieve all assets that were transferred since the bug was present and + # use media files + asset_uids = Asset.objects.filter( + Q( + pk__in=AssetFile.objects.values_list('asset_id', flat=True).exclude( + file_type=AssetFile.PAIRED_DATA + ) + ) + & Q( + pk__in=Transfer.objects.values_list('asset_id', flat=True).filter( + invite__date_created__date__gte='2024-09-15' + ) + ) + ).values_list('uid', flat=True) + + username_subquery = XForm.objects.filter(pk=OuterRef('xform_id')).values( + 'user__username' + )[:1] + + # Step 2: Iterate through relevant MetaData objects and fix their data_file fields + for metadata in ( + MetaData.objects.filter( + xform_id__in=XForm.objects.filter( + kpi_asset_uid__in=list(asset_uids) + ), + ) + .exclude( + Q(data_file__startswith=Subquery(username_subquery)) + | Q(data_file__isnull=True) + | Q(data_file='') + ) + .select_related('xform', 'xform__user') + .iterator() + ): + data_file = str(metadata.data_file) + old_username, *other_parts = data_file.split('/') + other_parts.insert(0, metadata.xform.user.username) + metadata.data_file = '/'.join(other_parts) + metadata.save(update_fields=['data_file']) diff --git a/kobo/apps/long_running_migrations/migrations/0002_fix_failed_project_ownership_transfer_with_media_files.py b/kobo/apps/long_running_migrations/migrations/0002_fix_failed_project_ownership_transfer_with_media_files.py new file mode 100644 index 0000000000..fa1f74df36 --- /dev/null +++ b/kobo/apps/long_running_migrations/migrations/0002_fix_failed_project_ownership_transfer_with_media_files.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.15 on 2024-12-18 20:00 + +from django.db import migrations + + +def add_long_running_migration(apps, schema_editor): + LongRunningMigration = apps.get_model('long_running_migrations', 'LongRunningMigration') # noqa + LongRunningMigration.objects.create( + name='0002_fix_project_ownership_transfer_with_media_files' + ) + + +def noop(*args, **kwargs): + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('long_running_migrations', '0001_initial'), + ] + + operations = [ + migrations.RunPython(add_long_running_migration, noop), + ]