# Generated by Django 1.11.28 on 2020-07-28 16:24

from django.db import migrations
from django.db.models import Min

from sentry.utils.query import RangeQuerySetWrapper


def cleanup_event_attachment_files(apps, schema_editor):
    """
    Previously, cleanup task code did a SQL bulk delete on EventAttachment
    leaving orphaned File and FileBlob objects. These orphaned files now need to
    be purged as they are still consuming space.
    """
    EventAttachment = apps.get_model("sentry", "EventAttachment")
    File = apps.get_model("sentry", "File")

    # Find the oldest live attachment as we only want to purge old files.
    # If there are not files skip everything.
    oldest_attachment = EventAttachment.objects.all().aggregate(Min("date_added"))
    if not oldest_attachment or oldest_attachment["date_added__min"] is None:
        return

    # File types used in event attachments.
    attachment_types = [
        "event.applecrashreport",
        "event.attachment",
        "event.payload",
        "event.minidump",
        "unreal.context",
        "unreal.logs",
    ]
    file_query = File.objects.filter(timestamp__lt=oldest_attachment["date_added__min"]).filter(
        type__in=attachment_types
    )

    for f in RangeQuerySetWrapper(file_query):
        # Double check that the file is not referenced.
        if not EventAttachment.objects.filter(file=f).exists():
            f.delete()


class Migration(migrations.Migration):
    # This flag is used to mark that a migration shouldn't be automatically run in
    # production. We set this to True for operations that we think are risky and want
    # someone from ops to run manually and monitor.
    # General advice is that if in doubt, mark your migration as `is_dangerous`.
    # Some things you should always mark as dangerous:
    # - Large data migrations. Typically we want these to be run manually by ops so that
    #   they can be monitored. Since data migrations will now hold a transaction open
    #   this is even more important.
    # - Adding columns to highly active tables, even ones that are NULL.
    is_dangerous = True

    # This flag is used to decide whether to run this migration in a transaction or not.
    # By default we prefer to run in a transaction, but for migrations where you want
    # to `CREATE INDEX CONCURRENTLY` this needs to be set to False. Typically you'll
    # want to create an index concurrently when adding one to an existing table.
    atomic = False

    dependencies = [
        ("sentry", "0093_make_identity_user_id_textfield"),
    ]

    operations = [
        migrations.RunPython(
            code=cleanup_event_attachment_files, reverse_code=migrations.RunPython.noop
        )
    ]
