mirror of
https://github.com/gmfricke/cmmc_audit.git
synced 2026-06-28 19:53:04 -06:00
Consolidate initial audit migration
This commit is contained in:
parent
73bf84e651
commit
a86f97c78b
8 changed files with 183 additions and 247 deletions
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 5.2.14 on 2026-05-19 20:29
|
||||
# Generated by Django 5.2.14 on 2026-05-27
|
||||
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
|
@ -15,24 +16,190 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AuditEvent',
|
||||
name="AuditEvent",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||
('action', models.CharField(choices=[('admin_addition', 'Admin addition'), ('admin_change', 'Admin change'), ('admin_deletion', 'Admin deletion')], max_length=64)),
|
||||
('target_type', models.CharField(blank=True, max_length=128)),
|
||||
('target_id', models.CharField(blank=True, max_length=128)),
|
||||
('target_repr', models.CharField(blank=True, max_length=255)),
|
||||
('old_values', models.JSONField(blank=True, default=dict)),
|
||||
('new_values', models.JSONField(blank=True, default=dict)),
|
||||
('message', models.TextField(blank=True)),
|
||||
('request_path', models.CharField(blank=True, max_length=255)),
|
||||
('ip_address', models.GenericIPAddressField(blank=True, null=True)),
|
||||
('actor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='cmmc_audit_events', to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("timestamp", models.DateTimeField(auto_now_add=True)),
|
||||
("event_time", models.DateTimeField(default=django.utils.timezone.now)),
|
||||
(
|
||||
"action",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("admin_addition", "Admin addition"),
|
||||
("admin_change", "Admin change"),
|
||||
("admin_deletion", "Admin deletion"),
|
||||
("user_pi_upgraded", "User upgraded to PI"),
|
||||
("pi_status_revoked", "PI status revoked"),
|
||||
(
|
||||
"user_admin_privileges_changed",
|
||||
"User admin privileges changed",
|
||||
),
|
||||
("allocation_requested", "Allocation created/requested"),
|
||||
(
|
||||
"allocation_change_requested",
|
||||
"Allocation change requested",
|
||||
),
|
||||
(
|
||||
"allocation_status_changed",
|
||||
"Allocation status changed",
|
||||
),
|
||||
("allocation_disabled", "Allocation disabled"),
|
||||
("renewal_requested", "Renewal requested"),
|
||||
("renewal_approved", "Renewal approved"),
|
||||
("allocation_renewed", "Allocation renewed"),
|
||||
("project_user_added", "Project user added"),
|
||||
("project_user_removed", "Project user removed"),
|
||||
(
|
||||
"project_user_role_changed",
|
||||
"Project user role changed",
|
||||
),
|
||||
("project_created", "Project created"),
|
||||
("project_archived", "Project archived"),
|
||||
("project_deleted", "Project deleted"),
|
||||
("project_status_changed", "Project status changed"),
|
||||
("project_pi_changed", "Project PI changed"),
|
||||
("project_review_forced", "Project review forced"),
|
||||
(
|
||||
"project_review_submitted",
|
||||
"Project review submitted",
|
||||
),
|
||||
(
|
||||
"project_review_completed",
|
||||
"Project review completed",
|
||||
),
|
||||
(
|
||||
"project_review_status_changed",
|
||||
"Project review status changed",
|
||||
),
|
||||
("resource_created", "Resource created"),
|
||||
("resource_changed", "Resource changed"),
|
||||
("resource_deleted", "Resource deleted"),
|
||||
],
|
||||
max_length=64,
|
||||
),
|
||||
),
|
||||
(
|
||||
"evidence_category",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("AC-Access-Control", "AC - Access Control"),
|
||||
(
|
||||
"AU-Audit-Accountability",
|
||||
"AU - Audit and Accountability",
|
||||
),
|
||||
(
|
||||
"AC-Access-Control; AU-Audit-Accountability",
|
||||
"AC/AU - Access and Audit",
|
||||
),
|
||||
(
|
||||
"CM-Configuration-Management",
|
||||
"CM - Configuration Management",
|
||||
),
|
||||
(
|
||||
"IA-Identification-Authentication",
|
||||
"IA - Identification and Authentication",
|
||||
),
|
||||
],
|
||||
max_length=128,
|
||||
),
|
||||
),
|
||||
("control_family", models.CharField(blank=True, max_length=16)),
|
||||
("target_type", models.CharField(blank=True, max_length=128)),
|
||||
("target_id", models.CharField(blank=True, max_length=128)),
|
||||
("target_repr", models.CharField(blank=True, max_length=255)),
|
||||
("old_values", models.JSONField(blank=True, default=dict)),
|
||||
("new_values", models.JSONField(blank=True, default=dict)),
|
||||
("message", models.TextField(blank=True)),
|
||||
(
|
||||
"source",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("runtime", "Runtime"),
|
||||
("django_admin", "Django admin"),
|
||||
("coldfront_signal", "ColdFront signal"),
|
||||
("coldfront_workflow", "ColdFront workflow"),
|
||||
(
|
||||
"reconstructed_django_admin_log",
|
||||
"Reconstructed Django admin log",
|
||||
),
|
||||
("django_admin_log", "Django admin log"),
|
||||
("coldfront_history", "ColdFront history"),
|
||||
],
|
||||
default="runtime",
|
||||
max_length=64,
|
||||
),
|
||||
),
|
||||
("source_id", models.CharField(blank=True, max_length=128)),
|
||||
("is_reconstructed", models.BooleanField(default=False)),
|
||||
("request_path", models.CharField(blank=True, max_length=255)),
|
||||
("ip_address", models.GenericIPAddressField(blank=True, null=True)),
|
||||
(
|
||||
"actor",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="cmmc_audit_events",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-timestamp'],
|
||||
'indexes': [models.Index(fields=['timestamp'], name='cmmc_audit__timesta_8969da_idx'), models.Index(fields=['action'], name='cmmc_audit__action_80997f_idx'), models.Index(fields=['actor'], name='cmmc_audit__actor_i_6096a0_idx'), models.Index(fields=['target_type', 'target_id'], name='cmmc_audit__target__4e5508_idx')],
|
||||
"ordering": ["-timestamp"],
|
||||
"indexes": [
|
||||
models.Index(
|
||||
fields=["event_time"], name="cmmc_audit__event_t_752462_idx"
|
||||
),
|
||||
models.Index(
|
||||
fields=["action"], name="cmmc_audit__action_80997f_idx"
|
||||
),
|
||||
models.Index(
|
||||
fields=["evidence_category"],
|
||||
name="cmmc_audit__evidenc_404a75_idx",
|
||||
),
|
||||
models.Index(
|
||||
fields=["source"], name="cmmc_audit__source_21deb0_idx"
|
||||
),
|
||||
models.Index(
|
||||
fields=["actor"], name="cmmc_audit__actor_i_6096a0_idx"
|
||||
),
|
||||
models.Index(
|
||||
fields=["target_type", "target_id"],
|
||||
name="cmmc_audit__target__4e5508_idx",
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="BackfillRun",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=128, unique=True)),
|
||||
("started", models.DateTimeField(auto_now_add=True)),
|
||||
("completed", models.DateTimeField(blank=True, null=True)),
|
||||
("created_events", models.PositiveIntegerField(default=0)),
|
||||
("dry_run", models.BooleanField(default=False)),
|
||||
("notes", models.TextField(blank=True)),
|
||||
],
|
||||
options={
|
||||
"ordering": ["-started"],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 5.2.14 on 2026-05-19 20:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cmmc_audit', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='auditevent',
|
||||
name='action',
|
||||
field=models.CharField(choices=[('admin_addition', 'Admin addition'), ('admin_change', 'Admin change'), ('admin_deletion', 'Admin deletion'), ('user_pi_upgraded', 'User upgraded to PI'), ('pi_status_revoked', 'PI status revoked'), ('allocation_requested', 'Allocation created/requested'), ('allocation_status_changed', 'Allocation status changed'), ('allocation_renewed', 'Allocation renewed'), ('project_user_added', 'Project user added'), ('project_user_removed', 'Project user removed'), ('project_user_role_changed', 'Project user role changed')], max_length=64),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 5.2.14 on 2026-05-19 20:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cmmc_audit', '0002_alter_auditevent_action'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='auditevent',
|
||||
name='action',
|
||||
field=models.CharField(choices=[('admin_addition', 'Admin addition'), ('admin_change', 'Admin change'), ('admin_deletion', 'Admin deletion'), ('user_pi_upgraded', 'User upgraded to PI'), ('pi_status_revoked', 'PI status revoked'), ('user_admin_privileges_changed', 'User admin privileges changed'), ('allocation_requested', 'Allocation created/requested'), ('allocation_change_requested', 'Allocation change requested'), ('allocation_status_changed', 'Allocation status changed'), ('renewal_requested', 'Renewal requested'), ('renewal_approved', 'Renewal approved'), ('allocation_renewed', 'Allocation renewed'), ('project_user_added', 'Project user added'), ('project_user_removed', 'Project user removed'), ('project_user_role_changed', 'Project user role changed'), ('resource_created', 'Resource created'), ('resource_changed', 'Resource changed'), ('resource_deleted', 'Resource deleted')], max_length=64),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 5.2.14 on 2026-05-20 02:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cmmc_audit', '0003_alter_auditevent_action'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='auditevent',
|
||||
name='action',
|
||||
field=models.CharField(choices=[('admin_addition', 'Admin addition'), ('admin_change', 'Admin change'), ('admin_deletion', 'Admin deletion'), ('user_pi_upgraded', 'User upgraded to PI'), ('pi_status_revoked', 'PI status revoked'), ('user_admin_privileges_changed', 'User admin privileges changed'), ('allocation_requested', 'Allocation created/requested'), ('allocation_change_requested', 'Allocation change requested'), ('allocation_status_changed', 'Allocation status changed'), ('allocation_disabled', 'Allocation disabled'), ('renewal_requested', 'Renewal requested'), ('renewal_approved', 'Renewal approved'), ('allocation_renewed', 'Allocation renewed'), ('project_user_added', 'Project user added'), ('project_user_removed', 'Project user removed'), ('project_user_role_changed', 'Project user role changed'), ('resource_created', 'Resource created'), ('resource_changed', 'Resource changed'), ('resource_deleted', 'Resource deleted')], max_length=64),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 5.2.14 on 2026-05-20 04:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cmmc_audit', '0004_alter_auditevent_action'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='auditevent',
|
||||
name='action',
|
||||
field=models.CharField(choices=[('admin_addition', 'Admin addition'), ('admin_change', 'Admin change'), ('admin_deletion', 'Admin deletion'), ('user_pi_upgraded', 'User upgraded to PI'), ('pi_status_revoked', 'PI status revoked'), ('user_admin_privileges_changed', 'User admin privileges changed'), ('allocation_requested', 'Allocation created/requested'), ('allocation_change_requested', 'Allocation change requested'), ('allocation_status_changed', 'Allocation status changed'), ('allocation_disabled', 'Allocation disabled'), ('renewal_requested', 'Renewal requested'), ('renewal_approved', 'Renewal approved'), ('allocation_renewed', 'Allocation renewed'), ('project_user_added', 'Project user added'), ('project_user_removed', 'Project user removed'), ('project_user_role_changed', 'Project user role changed'), ('project_review_forced', 'Project review forced'), ('project_review_submitted', 'Project review submitted'), ('project_review_completed', 'Project review completed'), ('project_review_status_changed', 'Project review status changed'), ('resource_created', 'Resource created'), ('resource_changed', 'Resource changed'), ('resource_deleted', 'Resource deleted')], max_length=64),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
# Generated by Django 5.2.14 on 2026-05-20 22:17
|
||||
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
ACTION_EVIDENCE_MAP = {
|
||||
"admin_addition": ("AU-Audit-Accountability", "AU", "django_admin"),
|
||||
"admin_change": ("AU-Audit-Accountability", "AU", "django_admin"),
|
||||
"admin_deletion": ("AU-Audit-Accountability", "AU", "django_admin"),
|
||||
"user_pi_upgraded": ("AC-Access-Control", "AC", "runtime"),
|
||||
"pi_status_revoked": ("AC-Access-Control", "AC", "runtime"),
|
||||
"user_admin_privileges_changed": ("AC-Access-Control", "AC", "runtime"),
|
||||
"allocation_requested": ("AC-Access-Control; AU-Audit-Accountability", "AC,AU", "runtime"),
|
||||
"allocation_change_requested": ("AC-Access-Control; AU-Audit-Accountability", "AC,AU", "runtime"),
|
||||
"allocation_status_changed": ("AC-Access-Control; AU-Audit-Accountability", "AC,AU", "runtime"),
|
||||
"allocation_disabled": ("AC-Access-Control; AU-Audit-Accountability", "AC,AU", "runtime"),
|
||||
"renewal_requested": ("AC-Access-Control; AU-Audit-Accountability", "AC,AU", "runtime"),
|
||||
"renewal_approved": ("AC-Access-Control; AU-Audit-Accountability", "AC,AU", "runtime"),
|
||||
"allocation_renewed": ("AC-Access-Control; AU-Audit-Accountability", "AC,AU", "runtime"),
|
||||
"project_user_added": ("AC-Access-Control", "AC", "runtime"),
|
||||
"project_user_removed": ("AC-Access-Control", "AC", "runtime"),
|
||||
"project_user_role_changed": ("AC-Access-Control", "AC", "runtime"),
|
||||
"project_review_forced": ("AU-Audit-Accountability", "AU", "runtime"),
|
||||
"project_review_submitted": ("AU-Audit-Accountability", "AU", "runtime"),
|
||||
"project_review_completed": ("AU-Audit-Accountability", "AU", "runtime"),
|
||||
"project_review_status_changed": ("AU-Audit-Accountability", "AU", "runtime"),
|
||||
"resource_created": ("CM-Configuration-Management", "CM", "runtime"),
|
||||
"resource_changed": ("CM-Configuration-Management", "CM", "runtime"),
|
||||
"resource_deleted": ("CM-Configuration-Management", "CM", "runtime"),
|
||||
}
|
||||
|
||||
|
||||
def backfill_cmmc_fields(apps, schema_editor):
|
||||
AuditEvent = apps.get_model("cmmc_audit", "AuditEvent")
|
||||
for event in AuditEvent.objects.all().iterator():
|
||||
evidence_category, control_family, source = ACTION_EVIDENCE_MAP.get(event.action, ("", "", "runtime"))
|
||||
event.event_time = event.timestamp
|
||||
event.evidence_category = evidence_category
|
||||
event.control_family = control_family
|
||||
event.source = source
|
||||
event.save(
|
||||
update_fields=[
|
||||
"event_time",
|
||||
"evidence_category",
|
||||
"control_family",
|
||||
"source",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cmmc_audit', '0005_alter_auditevent_action'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveIndex(
|
||||
model_name='auditevent',
|
||||
name='cmmc_audit__timesta_8969da_idx',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='auditevent',
|
||||
name='control_family',
|
||||
field=models.CharField(blank=True, max_length=16),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='auditevent',
|
||||
name='event_time',
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='auditevent',
|
||||
name='evidence_category',
|
||||
field=models.CharField(blank=True, choices=[('AC-Access-Control', 'AC - Access Control'), ('AU-Audit-Accountability', 'AU - Audit and Accountability'), ('AC-Access-Control; AU-Audit-Accountability', 'AC/AU - Access and Audit'), ('CM-Configuration-Management', 'CM - Configuration Management'), ('IA-Identification-Authentication', 'IA - Identification and Authentication')], max_length=128),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='auditevent',
|
||||
name='is_reconstructed',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='auditevent',
|
||||
name='source',
|
||||
field=models.CharField(choices=[('runtime', 'Runtime'), ('django_admin', 'Django admin'), ('coldfront_signal', 'ColdFront signal'), ('coldfront_workflow', 'ColdFront workflow'), ('reconstructed_django_admin_log', 'Reconstructed Django admin log')], default='runtime', max_length=64),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='auditevent',
|
||||
name='source_id',
|
||||
field=models.CharField(blank=True, max_length=128),
|
||||
),
|
||||
migrations.RunPython(backfill_cmmc_fields, migrations.RunPython.noop),
|
||||
migrations.AddIndex(
|
||||
model_name='auditevent',
|
||||
index=models.Index(fields=['event_time'], name='cmmc_audit__event_t_752462_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='auditevent',
|
||||
index=models.Index(fields=['evidence_category'], name='cmmc_audit__evidenc_404a75_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='auditevent',
|
||||
index=models.Index(fields=['source'], name='cmmc_audit__source_21deb0_idx'),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
# Generated by Django 5.2.14 on 2026-05-20 23:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cmmc_audit', '0006_add_cmmc_evidence_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BackfillRun',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128, unique=True)),
|
||||
('started', models.DateTimeField(auto_now_add=True)),
|
||||
('completed', models.DateTimeField(blank=True, null=True)),
|
||||
('created_events', models.PositiveIntegerField(default=0)),
|
||||
('dry_run', models.BooleanField(default=False)),
|
||||
('notes', models.TextField(blank=True)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-started'],
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='auditevent',
|
||||
name='source',
|
||||
field=models.CharField(choices=[('runtime', 'Runtime'), ('django_admin', 'Django admin'), ('coldfront_signal', 'ColdFront signal'), ('coldfront_workflow', 'ColdFront workflow'), ('reconstructed_django_admin_log', 'Reconstructed Django admin log'), ('django_admin_log', 'Django admin log'), ('coldfront_history', 'ColdFront history')], default='runtime', max_length=64),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 5.2.14 on 2026-05-21 02:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cmmc_audit', '0007_backfillrun_alter_auditevent_source'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='auditevent',
|
||||
name='action',
|
||||
field=models.CharField(choices=[('admin_addition', 'Admin addition'), ('admin_change', 'Admin change'), ('admin_deletion', 'Admin deletion'), ('user_pi_upgraded', 'User upgraded to PI'), ('pi_status_revoked', 'PI status revoked'), ('user_admin_privileges_changed', 'User admin privileges changed'), ('allocation_requested', 'Allocation created/requested'), ('allocation_change_requested', 'Allocation change requested'), ('allocation_status_changed', 'Allocation status changed'), ('allocation_disabled', 'Allocation disabled'), ('renewal_requested', 'Renewal requested'), ('renewal_approved', 'Renewal approved'), ('allocation_renewed', 'Allocation renewed'), ('project_user_added', 'Project user added'), ('project_user_removed', 'Project user removed'), ('project_user_role_changed', 'Project user role changed'), ('project_created', 'Project created'), ('project_archived', 'Project archived'), ('project_deleted', 'Project deleted'), ('project_status_changed', 'Project status changed'), ('project_pi_changed', 'Project PI changed'), ('project_review_forced', 'Project review forced'), ('project_review_submitted', 'Project review submitted'), ('project_review_completed', 'Project review completed'), ('project_review_status_changed', 'Project review status changed'), ('resource_created', 'Resource created'), ('resource_changed', 'Resource changed'), ('resource_deleted', 'Resource deleted')], max_length=64),
|
||||
),
|
||||
]
|
||||
Loading…
Add table
Reference in a new issue