feat: add enterprise identity and channel integrations
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# Generated by Django 5.2.15 on 2026-07-27 08:41
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0002_reorganize_navigation_menus'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='EnterpriseIdentityProvider',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('slug', models.SlugField(max_length=80, unique=True)),
|
||||
('name', models.CharField(max_length=120)),
|
||||
('provider_type', models.CharField(choices=[('oidc', 'OpenID Connect'), ('ldap', 'LDAP')], default='oidc', max_length=20)),
|
||||
('enabled', models.BooleanField(default=False)),
|
||||
('button_label', models.CharField(blank=True, max_length=120)),
|
||||
('issuer', models.URLField(blank=True, max_length=500)),
|
||||
('metadata_url', models.URLField(blank=True, max_length=500)),
|
||||
('client_id', models.CharField(blank=True, max_length=255)),
|
||||
('credential_encrypted', models.TextField(blank=True)),
|
||||
('scopes', models.JSONField(blank=True, default=list)),
|
||||
('claim_mappings', models.JSONField(blank=True, default=dict)),
|
||||
('configuration', models.JSONField(blank=True, default=dict)),
|
||||
('auto_create_users', models.BooleanField(default=True)),
|
||||
('sync_profile', models.BooleanField(default=True)),
|
||||
('sync_groups', models.BooleanField(default=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_identity_providers', to=settings.AUTH_USER_MODEL)),
|
||||
('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='updated_identity_providers', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name', 'id'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EnterpriseGroupMapping',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('external_group', models.CharField(max_length=255)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('user_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='enterprise_identity_mappings', to='accounts.usergroup')),
|
||||
('provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='group_mappings', to='accounts.enterpriseidentityprovider')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['provider_id', 'external_group'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EnterpriseDirectorySyncRun',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('status', models.CharField(choices=[('running', '运行中'), ('completed', '已完成'), ('partial', '部分完成'), ('failed', '失败')], default='running', max_length=20)),
|
||||
('total_count', models.PositiveIntegerField(default=0)),
|
||||
('created_count', models.PositiveIntegerField(default=0)),
|
||||
('updated_count', models.PositiveIntegerField(default=0)),
|
||||
('failed_count', models.PositiveIntegerField(default=0)),
|
||||
('errors', models.JSONField(blank=True, default=list)),
|
||||
('started_at', models.DateTimeField(auto_now_add=True)),
|
||||
('finished_at', models.DateTimeField(blank=True, null=True)),
|
||||
('initiated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='enterprise_directory_sync_runs', to=settings.AUTH_USER_MODEL)),
|
||||
('provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='directory_sync_runs', to='accounts.enterpriseidentityprovider')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-started_at', '-id'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ExternalIdentity',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('subject', models.CharField(max_length=255)),
|
||||
('claims_snapshot', models.JSONField(blank=True, default=dict)),
|
||||
('last_login_at', models.DateTimeField(blank=True, null=True)),
|
||||
('last_synced_at', models.DateTimeField(blank=True, null=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='external_identities', to='accounts.enterpriseidentityprovider')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='external_identities', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['provider_id', 'subject'],
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='enterpriseidentityprovider',
|
||||
index=models.Index(fields=['provider_type', 'enabled'], name='acct_idp_type_enabled_idx'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='enterprisegroupmapping',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'external_group'), name='acct_idp_external_group_uniq'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='enterprisedirectorysyncrun',
|
||||
index=models.Index(fields=['provider', 'started_at'], name='acct_dirsync_idp_started_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='externalidentity',
|
||||
index=models.Index(fields=['user', 'provider'], name='acct_identity_user_idp_idx'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='externalidentity',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'subject'), name='acct_identity_provider_subject_uniq'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='externalidentity',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'user'), name='acct_identity_provider_user_uniq'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,36 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def add_identity_menu(apps, schema_editor):
|
||||
menu_item = apps.get_model("accounts", "MenuItem")
|
||||
parent = menu_item.objects.filter(code="system").first()
|
||||
menu_item.objects.update_or_create(
|
||||
code="system.identity",
|
||||
defaults={
|
||||
"title": "企业身份",
|
||||
"path": "#/system/identity",
|
||||
"icon": "shield",
|
||||
"parent": parent,
|
||||
"sort_order": 50,
|
||||
"permission_code": "system.setting.manage",
|
||||
"is_visible": True,
|
||||
"is_enabled": True,
|
||||
},
|
||||
)
|
||||
menu_item.objects.filter(code="system.audit").update(sort_order=60)
|
||||
menu_item.objects.filter(code="system.design").update(sort_order=70)
|
||||
|
||||
|
||||
def remove_identity_menu(apps, schema_editor):
|
||||
menu_item = apps.get_model("accounts", "MenuItem")
|
||||
menu_item.objects.filter(code="system.identity").delete()
|
||||
menu_item.objects.filter(code="system.audit").update(sort_order=50)
|
||||
menu_item.objects.filter(code="system.design").update(sort_order=60)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("accounts", "0003_enterpriseidentityprovider_enterprisegroupmapping_and_more")]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(add_identity_menu, remove_identity_menu),
|
||||
]
|
||||
Reference in New Issue
Block a user