mirror of
https://github.com/yyhuni/xingrin.git
synced 2026-01-31 19:53:11 +08:00
- Consolidate common migrations into dedicated common app module - Remove asset search materialized view migration (0002) and simplify migration structure - Reorganize target detail page with new overview and settings sub-routes - Add target overview component displaying key asset information - Add target settings component for configuration management - Enhance scan history UI with improved data table and column definitions - Update scheduled scan dialog with better form handling - Refactor target service with improved API integration - Update scan hooks (use-scans, use-scheduled-scans) with better state management - Add internationalization strings for new target management features - Update Docker initialization and startup scripts for new app structure - Bump Django to 5.2.7 and update dependencies in requirements.txt - Add WeChat group contact information to README - Improve UI tabs component with better accessibility and styling
176 lines
12 KiB
Python
176 lines
12 KiB
Python
# Generated by Django 5.2.7 on 2026-01-06 00:55
|
||
|
||
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='SubfinderProviderSettings',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('providers', models.JSONField(default=dict, help_text='各 Provider 的 API Key 配置')),
|
||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||
('updated_at', models.DateTimeField(auto_now=True)),
|
||
],
|
||
options={
|
||
'verbose_name': 'Subfinder Provider 配置',
|
||
'verbose_name_plural': 'Subfinder Provider 配置',
|
||
'db_table': 'subfinder_provider_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"]')),
|
||
('yaml_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'],
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='ScanLog',
|
||
fields=[
|
||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||
('level', models.CharField(choices=[('info', 'Info'), ('warning', 'Warning'), ('error', 'Error')], default='info', help_text='日志级别', max_length=10)),
|
||
('content', models.TextField(help_text='日志内容')),
|
||
('created_at', models.DateTimeField(auto_now_add=True, db_index=True, help_text='创建时间')),
|
||
('scan', models.ForeignKey(help_text='关联的扫描任务', on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='scan.scan')),
|
||
],
|
||
options={
|
||
'verbose_name': '扫描日志',
|
||
'verbose_name_plural': '扫描日志',
|
||
'db_table': 'scan_log',
|
||
'ordering': ['created_at'],
|
||
},
|
||
),
|
||
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"]')),
|
||
('yaml_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'],
|
||
},
|
||
),
|
||
migrations.AddIndex(
|
||
model_name='scan',
|
||
index=models.Index(fields=['-created_at'], name='scan_created_0bb6c7_idx'),
|
||
),
|
||
migrations.AddIndex(
|
||
model_name='scan',
|
||
index=models.Index(fields=['target'], name='scan_target__718b9d_idx'),
|
||
),
|
||
migrations.AddIndex(
|
||
model_name='scan',
|
||
index=models.Index(fields=['deleted_at', '-created_at'], name='scan_deleted_eb17e8_idx'),
|
||
),
|
||
migrations.AddIndex(
|
||
model_name='scanlog',
|
||
index=models.Index(fields=['scan', 'created_at'], name='scan_log_scan_id_c4814a_idx'),
|
||
),
|
||
migrations.AddIndex(
|
||
model_name='scheduledscan',
|
||
index=models.Index(fields=['-created_at'], name='scheduled_s_created_9b9c2e_idx'),
|
||
),
|
||
migrations.AddIndex(
|
||
model_name='scheduledscan',
|
||
index=models.Index(fields=['is_enabled', '-created_at'], name='scheduled_s_is_enab_23d660_idx'),
|
||
),
|
||
migrations.AddIndex(
|
||
model_name='scheduledscan',
|
||
index=models.Index(fields=['name'], name='scheduled_s_name_bf332d_idx'),
|
||
),
|
||
]
|