# Generated by Django 3.2.8 on 2021-10-10 16:18

import uuid

import django.db.models.deletion
from django.apps.registry import Apps
from django.core.exceptions import FieldError
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor

import authentik.lib.models
import authentik.outposts.models


def fix_missing_token_identifier(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
    db_alias = schema_editor.connection.alias
    User = apps.get_model("authentik_core", "User")
    Token = apps.get_model("authentik_core", "Token")
    from authentik.outposts.models import Outpost

    for outpost in Outpost.objects.using(db_alias).all().only("pk"):
        user_identifier = outpost.user_identifier
        users = User.objects.using(db_alias).filter(username=user_identifier)
        if not users.exists():
            continue
        tokens = Token.objects.using(db_alias).filter(user=users.first())
        for token in tokens:
            if token.identifier != outpost.token_identifier:
                token.identifier = outpost.token_identifier
                token.save()


def migrate_to_service_connection(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
    db_alias = schema_editor.connection.alias
    Outpost = apps.get_model("authentik_outposts", "Outpost")
    DockerServiceConnection = apps.get_model("authentik_outposts", "DockerServiceConnection")
    KubernetesServiceConnection = apps.get_model(
        "authentik_outposts", "KubernetesServiceConnection"
    )

    docker = DockerServiceConnection.objects.using(db_alias).filter(local=True).first()
    k8s = KubernetesServiceConnection.objects.using(db_alias).filter(local=True).first()

    try:
        for outpost in Outpost.objects.using(db_alias).all().exclude(deployment_type="custom"):
            if outpost.deployment_type == "kubernetes":
                outpost.service_connection = k8s
            elif outpost.deployment_type == "docker":
                outpost.service_connection = docker
            outpost.save()
    except FieldError:
        # This is triggered during e2e tests when this function is called on an already-upgraded
        # schema
        pass


def remove_pb_prefix_users(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
    db_alias = schema_editor.connection.alias
    User = apps.get_model("authentik_core", "User")
    Outpost = apps.get_model("authentik_outposts", "Outpost")

    for outpost in Outpost.objects.using(db_alias).all():
        matching = User.objects.using(db_alias).filter(username=f"pb-outpost-{outpost.uuid.hex}")
        if matching.exists():
            matching.delete()


def update_config_prefix(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
    db_alias = schema_editor.connection.alias
    Outpost = apps.get_model("authentik_outposts", "Outpost")

    for outpost in Outpost.objects.using(db_alias).all():
        config = outpost._config
        for key in list(config):
            if "passbook" in key:
                new_key = key.replace("passbook", "authentik")
                config[new_key] = config[key]
                del config[key]
        outpost._config = config
        outpost.save()


class Migration(migrations.Migration):
    replaces = [
        ("authentik_outposts", "0001_initial"),
        ("authentik_outposts", "0002_auto_20200826_1306"),
        ("authentik_outposts", "0003_auto_20200827_2108"),
        ("authentik_outposts", "0004_auto_20200830_1056"),
        ("authentik_outposts", "0005_auto_20200909_1733"),
        ("authentik_outposts", "0006_auto_20201003_2239"),
        ("authentik_outposts", "0007_remove_outpost_channels"),
        ("authentik_outposts", "0008_auto_20201014_1547"),
        ("authentik_outposts", "0009_fix_missing_token_identifier"),
        ("authentik_outposts", "0010_service_connection"),
        ("authentik_outposts", "0011_docker_tls_auth"),
        ("authentik_outposts", "0012_service_connection_non_unique"),
        ("authentik_outposts", "0013_auto_20201203_2009"),
        ("authentik_outposts", "0014_auto_20201213_1407"),
        ("authentik_outposts", "0015_auto_20201224_1206"),
        ("authentik_outposts", "0016_alter_outpost_type"),
        ("authentik_outposts", "0017_outpost_managed"),
    ]

    initial = True

    dependencies = [
        ("authentik_core", "0014_auto_20201018_1158"),
        ("authentik_core", "0016_auto_20201202_2234"),
        ("authentik_crypto", "0002_create_self_signed_kp"),
        ("authentik_core", "0008_auto_20200824_1532"),
    ]

    operations = [
        migrations.CreateModel(
            name="Outpost",
            fields=[
                (
                    "uuid",
                    models.UUIDField(
                        default=uuid.uuid4, editable=False, primary_key=True, serialize=False
                    ),
                ),
                ("name", models.TextField()),
                ("providers", models.ManyToManyField(to="authentik_core.Provider")),
                (
                    "_config",
                    models.JSONField(default=authentik.outposts.models.default_outpost_config),
                ),
                ("type", models.TextField(choices=[("proxy", "Proxy")], default="proxy")),
                (
                    "deployment_type",
                    models.TextField(
                        choices=[
                            ("kubernetes", "Kubernetes"),
                            ("docker", "Docker"),
                            ("custom", "Custom"),
                        ],
                        default="custom",
                        help_text=(
                            "Select between authentik-managed deployment types or a custom"
                            " deployment."
                        ),
                    ),
                ),
            ],
        ),
        migrations.RunPython(
            code=fix_missing_token_identifier,
        ),
        migrations.CreateModel(
            name="OutpostServiceConnection",
            fields=[
                (
                    "uuid",
                    models.UUIDField(
                        default=uuid.uuid4, editable=False, primary_key=True, serialize=False
                    ),
                ),
                ("name", models.TextField()),
                (
                    "local",
                    models.BooleanField(
                        default=False,
                        help_text=(
                            "If enabled, use the local connection. Required Docker"
                            " socket/Kubernetes Integration"
                        ),
                        unique=True,
                    ),
                ),
            ],
        ),
        migrations.CreateModel(
            name="DockerServiceConnection",
            fields=[
                (
                    "outpostserviceconnection_ptr",
                    models.OneToOneField(
                        auto_created=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        parent_link=True,
                        primary_key=True,
                        serialize=False,
                        to="authentik_outposts.outpostserviceconnection",
                    ),
                ),
                ("url", models.TextField()),
                ("tls", models.BooleanField()),
            ],
            bases=("authentik_outposts.outpostserviceconnection",),
        ),
        migrations.CreateModel(
            name="KubernetesServiceConnection",
            fields=[
                (
                    "outpostserviceconnection_ptr",
                    models.OneToOneField(
                        auto_created=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        parent_link=True,
                        primary_key=True,
                        serialize=False,
                        to="authentik_outposts.outpostserviceconnection",
                    ),
                ),
                ("kubeconfig", models.JSONField()),
            ],
            bases=("authentik_outposts.outpostserviceconnection",),
        ),
        migrations.AddField(
            model_name="outpost",
            name="service_connection",
            field=models.ForeignKey(
                blank=True,
                default=None,
                help_text=(
                    "Select Service-Connection authentik should use to manage this outpost. Leave"
                    " empty if authentik should not handle the deployment."
                ),
                null=True,
                on_delete=django.db.models.deletion.SET_DEFAULT,
                to="authentik_outposts.outpostserviceconnection",
            ),
        ),
        migrations.RunPython(
            code=migrate_to_service_connection,
        ),
        migrations.RemoveField(
            model_name="outpost",
            name="deployment_type",
        ),
        migrations.AlterModelOptions(
            name="dockerserviceconnection",
            options={
                "verbose_name": "Docker Service-Connection",
                "verbose_name_plural": "Docker Service-Connections",
            },
        ),
        migrations.AlterModelOptions(
            name="kubernetesserviceconnection",
            options={
                "verbose_name": "Kubernetes Service-Connection",
                "verbose_name_plural": "Kubernetes Service-Connections",
            },
        ),
        migrations.AlterField(
            model_name="outpost",
            name="service_connection",
            field=authentik.lib.models.InheritanceForeignKey(
                blank=True,
                default=None,
                help_text=(
                    "Select Service-Connection authentik should use to manage this outpost. Leave"
                    " empty if authentik should not handle the deployment."
                ),
                null=True,
                on_delete=django.db.models.deletion.SET_DEFAULT,
                to="authentik_outposts.outpostserviceconnection",
            ),
        ),
        migrations.AlterModelOptions(
            name="outpostserviceconnection",
            options={
                "verbose_name": "Outpost Service-Connection",
                "verbose_name_plural": "Outpost Service-Connections",
            },
        ),
        migrations.AlterField(
            model_name="kubernetesserviceconnection",
            name="kubeconfig",
            field=models.JSONField(
                default=None,
                help_text=(
                    "Paste your kubeconfig here. authentik will automatically use the currently"
                    " selected context."
                ),
            ),
            preserve_default=False,
        ),
        migrations.RemoveField(
            model_name="dockerserviceconnection",
            name="tls",
        ),
        migrations.AddField(
            model_name="dockerserviceconnection",
            name="tls_authentication",
            field=models.ForeignKey(
                blank=True,
                default=None,
                help_text=(
                    "Certificate/Key used for authentication. Can be left empty for no"
                    " authentication."
                ),
                null=True,
                on_delete=django.db.models.deletion.SET_DEFAULT,
                related_name="+",
                to="authentik_crypto.certificatekeypair",
            ),
        ),
        migrations.AddField(
            model_name="dockerserviceconnection",
            name="tls_verification",
            field=models.ForeignKey(
                blank=True,
                default=None,
                help_text=(
                    "CA which the endpoint's Certificate is verified against. Can be left empty for"
                    " no validation."
                ),
                null=True,
                on_delete=django.db.models.deletion.SET_DEFAULT,
                related_name="+",
                to="authentik_crypto.certificatekeypair",
            ),
        ),
        migrations.AlterField(
            model_name="outpostserviceconnection",
            name="local",
            field=models.BooleanField(
                default=False,
                help_text=(
                    "If enabled, use the local connection. Required Docker socket/Kubernetes"
                    " Integration"
                ),
            ),
        ),
        migrations.RunPython(
            code=remove_pb_prefix_users,
        ),
        migrations.RunPython(
            code=update_config_prefix,
        ),
        migrations.AlterField(
            model_name="dockerserviceconnection",
            name="url",
            field=models.TextField(
                help_text=(
                    "Can be in the format of 'unix://<path>' when connecting to a local docker"
                    " daemon, or 'https://<hostname>:2376' when connecting to a remote system."
                )
            ),
        ),
        migrations.AlterField(
            model_name="kubernetesserviceconnection",
            name="kubeconfig",
            field=models.JSONField(
                blank=True,
                help_text=(
                    "Paste your kubeconfig here. authentik will automatically use the currently"
                    " selected context."
                ),
            ),
        ),
        migrations.AlterField(
            model_name="outpost",
            name="type",
            field=models.TextField(choices=[("proxy", "Proxy"), ("ldap", "Ldap")], default="proxy"),
        ),
        migrations.AddField(
            model_name="outpost",
            name="managed",
            field=models.TextField(
                default=None,
                help_text=(
                    "Objects which are managed by authentik. These objects are created and updated"
                    " automatically. This is flag only indicates that an object can be overwritten"
                    " by migrations. You can still modify the objects via the API, but expect"
                    " changes to be overwritten in a later update."
                ),
                null=True,
                unique=True,
                verbose_name="Managed by authentik",
            ),
        ),
    ]
