# Generated by Django 5.2.7 on 2026-01-02 04:45

import django.contrib.postgres.fields
import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('engine', '0001_initial'),
        ('targets', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='NotificationSettings',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('discord_enabled', models.BooleanField(default=False, help_text='是否启用 Discord 通知')),
                ('discord_webhook_url', models.URLField(blank=True, default='', help_text='Discord Webhook URL')),
                ('categories', models.JSONField(default=dict, help_text='各分类通知开关，如 {"scan": true, "vulnerability": true, "asset": true, "system": false}')),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('updated_at', models.DateTimeField(auto_now=True)),
            ],
            options={
                'verbose_name': '通知设置',
                'verbose_name_plural': '通知设置',
                'db_table': 'notification_settings',
            },
        ),
        migrations.CreateModel(
            name='Notification',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('category', models.CharField(choices=[('scan', '扫描任务'), ('vulnerability', '漏洞发现'), ('asset', '资产发现'), ('system', '系统消息')], db_index=True, default='system', help_text='通知分类', max_length=20)),
                ('level', models.CharField(choices=[('low', '低'), ('medium', '中'), ('high', '高'), ('critical', '严重')], db_index=True, default='low', help_text='通知级别', max_length=20)),
                ('title', models.CharField(help_text='通知标题', max_length=200)),
                ('message', models.CharField(help_text='通知内容', max_length=2000)),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('is_read', models.BooleanField(default=False, help_text='是否已读')),
                ('read_at', models.DateTimeField(blank=True, help_text='阅读时间', null=True)),
            ],
            options={
                'verbose_name': '通知',
                'verbose_name_plural': '通知',
                'db_table': 'notification',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['-created_at'], name='notificatio_created_c430f0_idx'), models.Index(fields=['category', '-created_at'], name='notificatio_categor_df0584_idx'), models.Index(fields=['level', '-created_at'], name='notificatio_level_0e5d12_idx'), models.Index(fields=['is_read', '-created_at'], name='notificatio_is_read_518ce0_idx')],
            },
        ),
        migrations.CreateModel(
            name='Scan',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('engine_ids', django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(), default=list, help_text='引擎 ID 列表', size=None)),
                ('engine_names', models.JSONField(default=list, help_text='引擎名称列表，如 ["引擎A", "引擎B"]')),
                ('merged_configuration', models.TextField(default='', help_text='合并后的 YAML 配置')),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='任务创建时间')),
                ('stopped_at', models.DateTimeField(blank=True, help_text='扫描结束时间', null=True)),
                ('status', models.CharField(choices=[('cancelled', '已取消'), ('completed', '已完成'), ('failed', '失败'), ('initiated', '初始化'), ('running', '运行中')], db_index=True, default='initiated', help_text='任务状态', max_length=20)),
                ('results_dir', models.CharField(blank=True, default='', help_text='结果存储目录', max_length=100)),
                ('container_ids', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, default=list, help_text='容器 ID 列表（Docker Container ID）', size=None)),
                ('error_message', models.CharField(blank=True, default='', help_text='错误信息', max_length=2000)),
                ('deleted_at', models.DateTimeField(blank=True, db_index=True, help_text='删除时间（NULL表示未删除）', null=True)),
                ('progress', models.IntegerField(default=0, help_text='扫描进度 0-100')),
                ('current_stage', models.CharField(blank=True, default='', help_text='当前扫描阶段', max_length=50)),
                ('stage_progress', models.JSONField(default=dict, help_text='各阶段进度详情')),
                ('cached_subdomains_count', models.IntegerField(default=0, help_text='缓存的子域名数量')),
                ('cached_websites_count', models.IntegerField(default=0, help_text='缓存的网站数量')),
                ('cached_endpoints_count', models.IntegerField(default=0, help_text='缓存的端点数量')),
                ('cached_ips_count', models.IntegerField(default=0, help_text='缓存的IP地址数量')),
                ('cached_directories_count', models.IntegerField(default=0, help_text='缓存的目录数量')),
                ('cached_vulns_total', models.IntegerField(default=0, help_text='缓存的漏洞总数')),
                ('cached_vulns_critical', models.IntegerField(default=0, help_text='缓存的严重漏洞数量')),
                ('cached_vulns_high', models.IntegerField(default=0, help_text='缓存的高危漏洞数量')),
                ('cached_vulns_medium', models.IntegerField(default=0, help_text='缓存的中危漏洞数量')),
                ('cached_vulns_low', models.IntegerField(default=0, help_text='缓存的低危漏洞数量')),
                ('stats_updated_at', models.DateTimeField(blank=True, help_text='统计数据最后更新时间', null=True)),
                ('target', models.ForeignKey(help_text='扫描目标', on_delete=django.db.models.deletion.CASCADE, related_name='scans', to='targets.target')),
                ('worker', models.ForeignKey(blank=True, help_text='执行扫描的 Worker 节点', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='scans', to='engine.workernode')),
            ],
            options={
                'verbose_name': '扫描任务',
                'verbose_name_plural': '扫描任务',
                'db_table': 'scan',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['-created_at'], name='scan_created_0bb6c7_idx'), models.Index(fields=['target'], name='scan_target__718b9d_idx'), models.Index(fields=['deleted_at', '-created_at'], name='scan_deleted_eb17e8_idx')],
            },
        ),
        migrations.CreateModel(
            name='ScheduledScan',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('name', models.CharField(help_text='任务名称', max_length=200)),
                ('engine_ids', django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(), default=list, help_text='引擎 ID 列表', size=None)),
                ('engine_names', models.JSONField(default=list, help_text='引擎名称列表，如 ["引擎A", "引擎B"]')),
                ('merged_configuration', models.TextField(default='', help_text='合并后的 YAML 配置')),
                ('cron_expression', models.CharField(default='0 2 * * *', help_text='Cron 表达式，格式：分 时 日 月 周', max_length=100)),
                ('is_enabled', models.BooleanField(db_index=True, default=True, help_text='是否启用')),
                ('run_count', models.IntegerField(default=0, help_text='已执行次数')),
                ('last_run_time', models.DateTimeField(blank=True, help_text='上次执行时间', null=True)),
                ('next_run_time', models.DateTimeField(blank=True, help_text='下次执行时间', null=True)),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='更新时间')),
                ('organization', models.ForeignKey(blank=True, help_text='扫描组织（设置后执行时动态获取组织下所有目标）', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_scans', to='targets.organization')),
                ('target', models.ForeignKey(blank=True, help_text='扫描单个目标（与 organization 二选一）', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_scans', to='targets.target')),
            ],
            options={
                'verbose_name': '定时扫描任务',
                'verbose_name_plural': '定时扫描任务',
                'db_table': 'scheduled_scan',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['-created_at'], name='scheduled_s_created_9b9c2e_idx'), models.Index(fields=['is_enabled', '-created_at'], name='scheduled_s_is_enab_23d660_idx'), models.Index(fields=['name'], name='scheduled_s_name_bf332d_idx')],
            },
        ),
    ]
