# Generated by Django 4.2.7 on 2023-12-23 22:51

import django.db.models.deletion
import multiselectfield.db.fields
from django.conf import settings
from django.contrib.auth.management import create_permissions
from django.db import migrations
from django.db import models
from django.db import transaction
from django.db.models import Q


def add_workflow_permissions(apps, schema_editor):
    app_name = "auth"
    User = apps.get_model(app_label=app_name, model_name="User")
    Group = apps.get_model(app_label=app_name, model_name="Group")
    Permission = apps.get_model(app_label=app_name, model_name="Permission")
    # create permissions without waiting for post_migrate signal
    for app_config in apps.get_app_configs():
        app_config.models_module = True
        create_permissions(app_config, apps=apps, verbosity=0)
        app_config.models_module = None

    add_permission = Permission.objects.get(codename="add_document")
    workflow_permissions = Permission.objects.filter(
        codename__contains="workflow",
    )

    for user in User.objects.filter(Q(user_permissions=add_permission)).distinct():
        user.user_permissions.add(*workflow_permissions)

    for group in Group.objects.filter(Q(permissions=add_permission)).distinct():
        group.permissions.add(*workflow_permissions)


def remove_workflow_permissions(apps, schema_editor):
    app_name = "auth"
    User = apps.get_model(app_label=app_name, model_name="User")
    Group = apps.get_model(app_label=app_name, model_name="Group")
    Permission = apps.get_model(app_label=app_name, model_name="Permission")
    workflow_permissions = Permission.objects.filter(
        codename__contains="workflow",
    )

    for user in User.objects.all():
        user.user_permissions.remove(*workflow_permissions)

    for group in Group.objects.all():
        group.permissions.remove(*workflow_permissions)


def migrate_consumption_templates(apps, schema_editor):
    """
    Migrate consumption templates to workflows. At this point ConsumptionTemplate still exists
    but objects are not returned as their true model so we have to manually do that
    """
    app_name = "documents"

    ConsumptionTemplate = apps.get_model(
        app_label=app_name,
        model_name="ConsumptionTemplate",
    )
    Workflow = apps.get_model(app_label=app_name, model_name="Workflow")
    WorkflowAction = apps.get_model(app_label=app_name, model_name="WorkflowAction")
    WorkflowTrigger = apps.get_model(app_label=app_name, model_name="WorkflowTrigger")
    DocumentType = apps.get_model(app_label=app_name, model_name="DocumentType")
    Correspondent = apps.get_model(app_label=app_name, model_name="Correspondent")
    StoragePath = apps.get_model(app_label=app_name, model_name="StoragePath")
    Tag = apps.get_model(app_label=app_name, model_name="Tag")
    CustomField = apps.get_model(app_label=app_name, model_name="CustomField")
    MailRule = apps.get_model(app_label="paperless_mail", model_name="MailRule")
    User = apps.get_model(app_label="auth", model_name="User")
    Group = apps.get_model(app_label="auth", model_name="Group")

    with transaction.atomic():
        for template in ConsumptionTemplate.objects.all():
            trigger = WorkflowTrigger(
                type=1,  # WorkflowTriggerType.CONSUMPTION
                sources=template.sources,
                filter_path=template.filter_path,
                filter_filename=template.filter_filename,
            )
            if template.filter_mailrule is not None:
                trigger.filter_mailrule = MailRule.objects.get(
                    id=template.filter_mailrule.id,
                )
            trigger.save()

            action = WorkflowAction.objects.create(
                assign_title=template.assign_title,
            )
            if template.assign_document_type is not None:
                action.assign_document_type = DocumentType.objects.get(
                    id=template.assign_document_type.id,
                )
            if template.assign_correspondent is not None:
                action.assign_correspondent = Correspondent.objects.get(
                    id=template.assign_correspondent.id,
                )
            if template.assign_storage_path is not None:
                action.assign_storage_path = StoragePath.objects.get(
                    id=template.assign_storage_path.id,
                )
            if template.assign_owner is not None:
                action.assign_owner = User.objects.get(id=template.assign_owner.id)
            if template.assign_tags is not None:
                action.assign_tags.set(
                    Tag.objects.filter(
                        id__in=[t.id for t in template.assign_tags.all()],
                    ).all(),
                )
            if template.assign_view_users is not None:
                action.assign_view_users.set(
                    User.objects.filter(
                        id__in=[u.id for u in template.assign_view_users.all()],
                    ).all(),
                )
            if template.assign_view_groups is not None:
                action.assign_view_groups.set(
                    Group.objects.filter(
                        id__in=[g.id for g in template.assign_view_groups.all()],
                    ).all(),
                )
            if template.assign_change_users is not None:
                action.assign_change_users.set(
                    User.objects.filter(
                        id__in=[u.id for u in template.assign_change_users.all()],
                    ).all(),
                )
            if template.assign_change_groups is not None:
                action.assign_change_groups.set(
                    Group.objects.filter(
                        id__in=[g.id for g in template.assign_change_groups.all()],
                    ).all(),
                )
            if template.assign_custom_fields is not None:
                action.assign_custom_fields.set(
                    CustomField.objects.filter(
                        id__in=[cf.id for cf in template.assign_custom_fields.all()],
                    ).all(),
                )
            action.save()

            workflow = Workflow.objects.create(
                name=template.name,
                order=template.order,
            )
            workflow.triggers.set([trigger])
            workflow.actions.set([action])
            workflow.save()


def unmigrate_consumption_templates(apps, schema_editor):
    app_name = "documents"

    ConsumptionTemplate = apps.get_model(
        app_label=app_name,
        model_name="ConsumptionTemplate",
    )
    Workflow = apps.get_model(app_label=app_name, model_name="Workflow")

    for workflow in Workflow.objects.all():
        template = ConsumptionTemplate.objects.create(
            name=workflow.name,
            order=workflow.order,
            sources=workflow.triggers.first().sources,
            filter_path=workflow.triggers.first().filter_path,
            filter_filename=workflow.triggers.first().filter_filename,
            filter_mailrule=workflow.triggers.first().filter_mailrule,
            assign_title=workflow.actions.first().assign_title,
            assign_document_type=workflow.actions.first().assign_document_type,
            assign_correspondent=workflow.actions.first().assign_correspondent,
            assign_storage_path=workflow.actions.first().assign_storage_path,
            assign_owner=workflow.actions.first().assign_owner,
        )
        template.assign_tags.set(workflow.actions.first().assign_tags.all())
        template.assign_view_users.set(workflow.actions.first().assign_view_users.all())
        template.assign_view_groups.set(
            workflow.actions.first().assign_view_groups.all(),
        )
        template.assign_change_users.set(
            workflow.actions.first().assign_change_users.all(),
        )
        template.assign_change_groups.set(
            workflow.actions.first().assign_change_groups.all(),
        )
        template.assign_custom_fields.set(
            workflow.actions.first().assign_custom_fields.all(),
        )
        template.save()


def delete_consumption_template_content_type(apps, schema_editor):
    with transaction.atomic():
        apps.get_model("contenttypes", "ContentType").objects.filter(
            app_label="documents",
            model="consumptiontemplate",
        ).delete()


def undelete_consumption_template_content_type(apps, schema_editor):
    apps.get_model("contenttypes", "ContentType").objects.create(
        app_label="documents",
        model="consumptiontemplate",
    )


class Migration(migrations.Migration):
    dependencies = [
        ("paperless_mail", "0023_remove_mailrule_filter_attachment_filename_and_more"),
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ("auth", "0012_alter_user_first_name_max_length"),
        ("documents", "1043_alter_savedviewfilterrule_rule_type"),
    ]

    operations = [
        migrations.CreateModel(
            name="Workflow",
            fields=[
                (
                    "id",
                    models.AutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                (
                    "name",
                    models.CharField(max_length=256, unique=True, verbose_name="name"),
                ),
                ("order", models.IntegerField(default=0, verbose_name="order")),
                (
                    "enabled",
                    models.BooleanField(default=True, verbose_name="enabled"),
                ),
            ],
        ),
        migrations.CreateModel(
            name="WorkflowAction",
            fields=[
                (
                    "id",
                    models.AutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                (
                    "type",
                    models.PositiveIntegerField(
                        choices=[(1, "Assignment")],
                        default=1,
                        verbose_name="Workflow Action Type",
                    ),
                ),
                (
                    "assign_title",
                    models.CharField(
                        blank=True,
                        help_text="Assign a document title, can include some placeholders, see documentation.",
                        max_length=256,
                        null=True,
                        verbose_name="assign title",
                    ),
                ),
                (
                    "assign_change_groups",
                    models.ManyToManyField(
                        blank=True,
                        related_name="+",
                        to="auth.group",
                        verbose_name="grant change permissions to these groups",
                    ),
                ),
                (
                    "assign_change_users",
                    models.ManyToManyField(
                        blank=True,
                        related_name="+",
                        to=settings.AUTH_USER_MODEL,
                        verbose_name="grant change permissions to these users",
                    ),
                ),
                (
                    "assign_correspondent",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        to="documents.correspondent",
                        verbose_name="assign this correspondent",
                    ),
                ),
                (
                    "assign_custom_fields",
                    models.ManyToManyField(
                        blank=True,
                        related_name="+",
                        to="documents.customfield",
                        verbose_name="assign these custom fields",
                    ),
                ),
                (
                    "assign_document_type",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        to="documents.documenttype",
                        verbose_name="assign this document type",
                    ),
                ),
                (
                    "assign_owner",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        related_name="+",
                        to=settings.AUTH_USER_MODEL,
                        verbose_name="assign this owner",
                    ),
                ),
                (
                    "assign_storage_path",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        to="documents.storagepath",
                        verbose_name="assign this storage path",
                    ),
                ),
                (
                    "assign_tags",
                    models.ManyToManyField(
                        blank=True,
                        to="documents.tag",
                        verbose_name="assign this tag",
                    ),
                ),
                (
                    "assign_view_groups",
                    models.ManyToManyField(
                        blank=True,
                        related_name="+",
                        to="auth.group",
                        verbose_name="grant view permissions to these groups",
                    ),
                ),
                (
                    "assign_view_users",
                    models.ManyToManyField(
                        blank=True,
                        related_name="+",
                        to=settings.AUTH_USER_MODEL,
                        verbose_name="grant view permissions to these users",
                    ),
                ),
            ],
            options={
                "verbose_name": "workflow action",
                "verbose_name_plural": "workflow actions",
            },
        ),
        migrations.CreateModel(
            name="WorkflowTrigger",
            fields=[
                (
                    "id",
                    models.AutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                (
                    "type",
                    models.PositiveIntegerField(
                        choices=[
                            (1, "Consumption Started"),
                            (2, "Document Added"),
                            (3, "Document Updated"),
                        ],
                        default=1,
                        verbose_name="Workflow Trigger Type",
                    ),
                ),
                (
                    "sources",
                    multiselectfield.db.fields.MultiSelectField(
                        choices=[
                            (1, "Consume Folder"),
                            (2, "Api Upload"),
                            (3, "Mail Fetch"),
                        ],
                        default="1,2,3",
                        max_length=5,
                    ),
                ),
                (
                    "filter_path",
                    models.CharField(
                        blank=True,
                        help_text="Only consume documents with a path that matches this if specified. Wildcards specified as * are allowed. Case insensitive.",
                        max_length=256,
                        null=True,
                        verbose_name="filter path",
                    ),
                ),
                (
                    "filter_filename",
                    models.CharField(
                        blank=True,
                        help_text="Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
                        max_length=256,
                        null=True,
                        verbose_name="filter filename",
                    ),
                ),
                (
                    "filter_mailrule",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        to="paperless_mail.mailrule",
                        verbose_name="filter documents from this mail rule",
                    ),
                ),
                (
                    "matching_algorithm",
                    models.PositiveIntegerField(
                        choices=[
                            (0, "None"),
                            (1, "Any word"),
                            (2, "All words"),
                            (3, "Exact match"),
                            (4, "Regular expression"),
                            (5, "Fuzzy word"),
                        ],
                        default=0,
                        verbose_name="matching algorithm",
                    ),
                ),
                (
                    "match",
                    models.CharField(blank=True, max_length=256, verbose_name="match"),
                ),
                (
                    "is_insensitive",
                    models.BooleanField(default=True, verbose_name="is insensitive"),
                ),
                (
                    "filter_has_tags",
                    models.ManyToManyField(
                        blank=True,
                        to="documents.tag",
                        verbose_name="has these tag(s)",
                    ),
                ),
                (
                    "filter_has_document_type",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        to="documents.documenttype",
                        verbose_name="has this document type",
                    ),
                ),
                (
                    "filter_has_correspondent",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        to="documents.correspondent",
                        verbose_name="has this correspondent",
                    ),
                ),
            ],
            options={
                "verbose_name": "workflow trigger",
                "verbose_name_plural": "workflow triggers",
            },
        ),
        migrations.RunPython(
            add_workflow_permissions,
            remove_workflow_permissions,
        ),
        migrations.AddField(
            model_name="workflow",
            name="actions",
            field=models.ManyToManyField(
                related_name="workflows",
                to="documents.workflowaction",
                verbose_name="actions",
            ),
        ),
        migrations.AddField(
            model_name="workflow",
            name="triggers",
            field=models.ManyToManyField(
                related_name="workflows",
                to="documents.workflowtrigger",
                verbose_name="triggers",
            ),
        ),
        migrations.RunPython(
            migrate_consumption_templates,
            unmigrate_consumption_templates,
        ),
        migrations.DeleteModel("ConsumptionTemplate"),
        migrations.RunPython(
            delete_consumption_template_content_type,
            undelete_consumption_template_content_type,
        ),
    ]
