# Generated by Django 5.2.9 on 2026-01-11 03:20

import apps.base.models
import apps.nodes.models
import apps.sigils.fields
import django.contrib.auth.models
import django.db.migrations.operations.special
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.db.models import Q


# Functions from the following migrations need manual copying.
# Move them and any dependencies into this file, then update the
# RunPython operations to refer to the local versions:
# apps.nodes.migrations.0004_remove_invalid_clipboard_tasks
# apps.nodes.migrations.0005_remove_seed_nodes
# apps.nodes.migrations.0009_remove_arthexis_self_node
# apps.nodes.migrations.0010_noderole_acronym


ACRONYM_MAP = {
    "Terminal": "TERM",
    "Control": "CTRL",
    "Satellite": "SATL",
    "Watchtower": "WTTW",
    "Constellation": "CONS",
}


def remove_invalid_clipboard_tasks(apps, schema_editor):
    try:
        PeriodicTask = apps.get_model("django_celery_beat", "PeriodicTask")
    except LookupError:
        return

    conditions = models.Q(task="nodes.tasks.sample_clipboard") | models.Q(
        name__icontains="poll-clipboard"
    )
    PeriodicTask.objects.filter(conditions).delete()


def remove_seed_nodes(apps, schema_editor):
    Node = apps.get_model("nodes", "Node")
    Node.objects.filter(is_seed_data=True).delete()


def remove_arthexis_self_node(apps, schema_editor):
    Node = apps.get_model("nodes", "Node")
    Node.objects.filter(
        Q(current_relation="SELF")
        & (
            Q(hostname="arthexis.com")
            | Q(network_hostname="arthexis.com")
            | Q(address="arthexis.com")
            | Q(public_endpoint="arthexis")
        )
    ).delete()


def assign_acronyms(apps, schema_editor):
    NodeRole = apps.get_model("nodes", "NodeRole")
    for name, acronym in ACRONYM_MAP.items():
        try:
            role = NodeRole.objects.get(name=name)
        except NodeRole.DoesNotExist:
            continue
        if role.acronym != acronym:
            role.acronym = acronym
            role.save(update_fields=["acronym"])


def remove_acronyms(apps, schema_editor):
    NodeRole = apps.get_model("nodes", "NodeRole")
    NodeRole.objects.all().update(acronym=None)


class Migration(migrations.Migration):

    replaces = [
        ("nodes", "0002_initial"),
        ("nodes", "0003_platform"),
        ("nodes", "0004_remove_invalid_clipboard_tasks"),
        ("nodes", "0005_remove_seed_nodes"),
        ("nodes", "0006_sshaccount"),
        ("nodes", "0007_node_base_site"),
        ("nodes", "0008_node_nodes_node_mac_address_unique"),
        ("nodes", "0009_remove_arthexis_self_node"),
        ("nodes", "0010_noderole_acronym"),
        ("nodes", "0011_netmessage_expires_at"),
    ]

    initial = False

    dependencies = [
        ("chats", "0003_initial"),
        ("django_celery_beat", "0001_initial"),
        ("groups", "0002_initial"),
        ("nodes", "0001_squashed_0001_initial"),
        ("sites", "0001_initial"),
        ("users", "0001_initial"),
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name="User",
            fields=[],
            options={
                "verbose_name": "User",
                "verbose_name_plural": "Users",
                "proxy": True,
                "indexes": [],
                "constraints": [],
            },
            bases=("users.user",),
            managers=[
                ("objects", apps.base.models.EntityUserManager()),
                ("all_objects", django.contrib.auth.models.UserManager()),
            ],
        ),
        migrations.AddField(
            model_name="netmessage",
            name="filter_node",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                related_name="filtered_net_messages",
                to="nodes.node",
                verbose_name="Node",
            ),
        ),
        migrations.AddField(
            model_name="netmessage",
            name="node_origin",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                related_name="originated_net_messages",
                to="nodes.node",
            ),
        ),
        migrations.AddField(
            model_name="netmessage",
            name="propagated_to",
            field=models.ManyToManyField(
                blank=True, related_name="received_net_messages", to="nodes.node"
            ),
        ),
        migrations.AddField(
            model_name="netmessage",
            name="filter_node_feature",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to="nodes.nodefeature",
                verbose_name="Node feature",
            ),
        ),
        migrations.AddField(
            model_name="nodefeatureassignment",
            name="feature",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="node_assignments",
                to="nodes.nodefeature",
            ),
        ),
        migrations.AddField(
            model_name="nodefeatureassignment",
            name="node",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="feature_assignments",
                to="nodes.node",
            ),
        ),
        migrations.AddField(
            model_name="node",
            name="features",
            field=models.ManyToManyField(
                blank=True,
                related_name="nodes",
                through="nodes.NodeFeatureAssignment",
                to="nodes.nodefeature",
            ),
        ),
        migrations.AddField(
            model_name="nodemanager",
            name="avatar",
            field=models.ForeignKey(
                blank=True,
                help_text="Avatar that owns this profile when not linked directly to a user or group.",
                null=True,
                on_delete=django.db.models.deletion.CASCADE,
                related_name="+",
                to="chats.chatavatar",
            ),
        ),
        migrations.AddField(
            model_name="nodemanager",
            name="group",
            field=models.OneToOneField(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.CASCADE,
                related_name="+",
                to="groups.securitygroup",
            ),
        ),
        migrations.AddField(
            model_name="nodemanager",
            name="user",
            field=models.OneToOneField(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.CASCADE,
                related_name="+",
                to=settings.AUTH_USER_MODEL,
            ),
        ),
        migrations.AddField(
            model_name="nodefeature",
            name="roles",
            field=models.ManyToManyField(
                blank=True, related_name="features", to="nodes.noderole"
            ),
        ),
        migrations.AddField(
            model_name="node",
            name="role",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to="nodes.noderole",
            ),
        ),
        migrations.AddField(
            model_name="netmessage",
            name="filter_node_role",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                related_name="filtered_net_messages",
                to="nodes.noderole",
                verbose_name="Node role",
            ),
        ),
        migrations.AddField(
            model_name="netmessage",
            name="reach",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to="nodes.noderole",
            ),
        ),
        migrations.AddField(
            model_name="nodeservice",
            name="feature",
            field=models.ForeignKey(
                blank=True,
                help_text="Limit this service to nodes with the selected feature.",
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to="nodes.nodefeature",
            ),
        ),
        migrations.AddField(
            model_name="pendingnetmessage",
            name="message",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="pending_deliveries",
                to="nodes.netmessage",
            ),
        ),
        migrations.AddField(
            model_name="pendingnetmessage",
            name="node",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="pending_messages",
                to="nodes.node",
            ),
        ),
        migrations.CreateModel(
            name="Platform",
            fields=[
                (
                    "id",
                    models.BigAutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                ("is_seed_data", models.BooleanField(default=False, editable=False)),
                ("is_user_data", models.BooleanField(default=False, editable=False)),
                ("is_deleted", models.BooleanField(default=False, editable=False)),
                ("name", models.CharField(max_length=100, unique=True)),
                ("hardware", models.CharField(max_length=100)),
                ("architecture", models.CharField(blank=True, max_length=50)),
                ("os_name", models.CharField(max_length=100)),
                ("os_version", models.CharField(max_length=50)),
            ],
            options={
                "ordering": ["name"],
                "verbose_name": "Platform",
                "verbose_name_plural": "Platforms",
                "constraints": [
                    models.UniqueConstraint(
                        fields=("hardware", "architecture", "os_name", "os_version"),
                        name="nodes_platform_hardware_os_unique",
                    )
                ],
            },
        ),
        migrations.RunPython(
            code=remove_invalid_clipboard_tasks,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.RunPython(
            code=remove_seed_nodes,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.CreateModel(
            name="SSHAccount",
            fields=[
                (
                    "id",
                    models.BigAutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                ("is_seed_data", models.BooleanField(default=False, editable=False)),
                ("is_user_data", models.BooleanField(default=False, editable=False)),
                ("is_deleted", models.BooleanField(default=False, editable=False)),
                ("username", models.CharField(max_length=150)),
                (
                    "password",
                    apps.sigils.fields.SigilShortAutoField(
                        blank=True,
                        help_text="Password for password-based authentication.",
                        max_length=255,
                    ),
                ),
                (
                    "private_key",
                    models.FileField(
                        blank=True,
                        help_text="Optional private key for key-based authentication.",
                        upload_to=apps.nodes.models.ssh_key_upload_path,
                    ),
                ),
                (
                    "public_key",
                    models.FileField(
                        blank=True,
                        help_text="Optional public key for key-based authentication.",
                        upload_to=apps.nodes.models.ssh_key_upload_path,
                    ),
                ),
                ("created_at", models.DateTimeField(auto_now_add=True)),
                ("updated_at", models.DateTimeField(auto_now=True)),
                (
                    "node",
                    models.ForeignKey(
                        on_delete=django.db.models.deletion.CASCADE,
                        related_name="ssh_accounts",
                        to="nodes.node",
                    ),
                ),
            ],
            options={
                "verbose_name": "SSH Account",
                "verbose_name_plural": "SSH Accounts",
                "ordering": ("username", "pk"),
                "unique_together": {("node", "username")},
            },
        ),
        migrations.AddField(
            model_name="node",
            name="base_site",
            field=models.ForeignKey(
                blank=True,
                help_text="Site that provides the preferred domain for this node.",
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                related_name="nodes",
                to="sites.site",
                verbose_name="Base site",
            ),
        ),
        migrations.AddConstraint(
            model_name="node",
            constraint=models.UniqueConstraint(
                condition=models.Q(("mac_address", ""), _negated=True),
                fields=("mac_address",),
                name="nodes_node_mac_address_unique",
            ),
        ),
        migrations.RunPython(
            code=remove_arthexis_self_node,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.AddField(
            model_name="noderole",
            name="acronym",
            field=models.CharField(blank=True, max_length=4, null=True, unique=True),
        ),
        migrations.RunPython(
            code=assign_acronyms,
            reverse_code=remove_acronyms,
        ),
        migrations.AddField(
            model_name="netmessage",
            name="expires_at",
            field=models.DateTimeField(
                blank=True,
                help_text="UTC timestamp after which this message should be discarded.",
                null=True,
            ),
        ),
    ]
