# Generated by Django 4.2.29 on 2026-03-18 12:11 from django.conf import settings from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ ('accounts', '0007_set_existing_users_must_change_password_false'), ] operations = [ migrations.AddField( model_name='loginrecord', name='geo_city', field=models.CharField(blank=True, default='', max_length=50, verbose_name='城市'), ), migrations.AddField( model_name='loginrecord', name='geo_country', field=models.CharField(blank=True, default='', max_length=50, verbose_name='国家'), ), migrations.AddField( model_name='loginrecord', name='geo_province', field=models.CharField(blank=True, default='', max_length=50, verbose_name='省份'), ), migrations.AddField( model_name='loginrecord', name='geo_source', field=models.CharField(blank=True, default='', max_length=10, verbose_name='归属地来源'), ), migrations.AddField( model_name='loginrecord', name='team', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='login_records', to='accounts.team', verbose_name='所属团队'), ), migrations.AddField( model_name='team', name='disabled_by', field=models.CharField(blank=True, default='', max_length=10, verbose_name='禁用来源'), ), migrations.AddField( model_name='team', name='expected_regions', field=models.CharField(blank=True, default='', max_length=500, verbose_name='预期登录城市(逗号分隔)'), ), migrations.AddField( model_name='user', name='disabled_by', field=models.CharField(blank=True, default='', max_length=10, verbose_name='禁用来源'), ), migrations.CreateModel( name='TeamAnomalyConfig', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('r1_enabled', models.BooleanField(blank=True, null=True, verbose_name='R1 开关')), ('r2_enabled', models.BooleanField(blank=True, null=True, verbose_name='R2 开关')), ('r2_window_seconds', models.IntegerField(blank=True, null=True, verbose_name='R2 时间窗口(秒)')), ('r3_enabled', models.BooleanField(blank=True, null=True, verbose_name='R3 开关')), ('r3_window_seconds', models.IntegerField(blank=True, null=True, verbose_name='R3 时间窗口(秒)')), ('r3_max_count', models.IntegerField(blank=True, null=True, verbose_name='R3 最大登录次数')), ('r4_enabled', models.BooleanField(blank=True, null=True, verbose_name='R4 开关')), ('r4_window_seconds', models.IntegerField(blank=True, null=True, verbose_name='R4 时间窗口(秒)')), ('r4_city_count', models.IntegerField(blank=True, null=True, verbose_name='R4 预期外城市数阈值')), ('r5_enabled', models.BooleanField(blank=True, null=True, verbose_name='R5 开关')), ('r5_days', models.IntegerField(blank=True, null=True, verbose_name='R5 统计天数')), ('r5_country_count', models.IntegerField(blank=True, null=True, verbose_name='R5 海外国家数阈值')), ('team', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='anomaly_config', to='accounts.team', verbose_name='团队')), ], options={ 'verbose_name': '团队异常检测配置', 'verbose_name_plural': '团队异常检测配置', }, ), migrations.CreateModel( name='LoginAnomaly', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('level', models.CharField(choices=[('warning', '警告'), ('critical', '严重')], max_length=10, verbose_name='严重程度')), ('rule', models.CharField(choices=[('region_mismatch', '登录地区不对'), ('impossible_travel', '不可能的旅行'), ('login_frequency', '登录太频繁'), ('multi_city', '团队遍地开花'), ('overseas_ip_diversity', '海外IP太杂')], max_length=30, verbose_name='触发规则')), ('detail', models.JSONField(default=dict, verbose_name='详情')), ('alerted', models.BooleanField(default=False, verbose_name='已发告警')), ('auto_disabled', models.BooleanField(default=False, verbose_name='已自动封禁')), ('disabled_target', models.CharField(blank=True, default='', max_length=10, verbose_name='封禁对象')), ('created_at', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='创建时间')), ('login_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='anomalies', to='accounts.loginrecord', verbose_name='触发登录记录')), ('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='login_anomalies', to='accounts.team', verbose_name='团队')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='login_anomalies', to=settings.AUTH_USER_MODEL, verbose_name='用户')), ], options={ 'verbose_name': '登录异常', 'verbose_name_plural': '登录异常', 'ordering': ['-created_at'], }, ), ]