mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 16:55:17 -05:00
Based on the git diff provided, here's a concise and descriptive commit message:
feat: add security event taxonomy and optimize park queryset - Add comprehensive security_event_types ChoiceGroup with categories for authentication, MFA, password, account, session, and API key events - Include severity levels, icons, and CSS classes for each event type - Fix park queryset optimization by using select_related for OneToOne location relationship - Remove location property fields (latitude/longitude) from values() call as they are not actual DB columns - Add proper location fields (city, state, country) to values() for map display This change enhances security event tracking capabilities and resolves a queryset optimization issue where property decorators were incorrectly used in values() queries.
This commit is contained in:
195
backend/apps/accounts/migrations/0017_add_security_log_model.py
Normal file
195
backend/apps/accounts/migrations/0017_add_security_log_model.py
Normal file
@@ -0,0 +1,195 @@
|
||||
# Generated by Django 5.2.10 on 2026-01-10 20:48
|
||||
|
||||
import apps.core.choices.fields
|
||||
import django.db.models.deletion
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("accounts", "0016_remove_emailverification_insert_insert_and_more"),
|
||||
("pghistory", "0007_auto_20250421_0444"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="SecurityLog",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
(
|
||||
"event_type",
|
||||
apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
choice_group="security_event_types",
|
||||
choices=[
|
||||
("login_success", "Login Success"),
|
||||
("login_failed", "Login Failed"),
|
||||
("logout", "Logout"),
|
||||
("mfa_enrolled", "MFA Enrolled"),
|
||||
("mfa_disabled", "MFA Disabled"),
|
||||
("mfa_challenge_success", "MFA Challenge Success"),
|
||||
("mfa_challenge_failed", "MFA Challenge Failed"),
|
||||
("passkey_registered", "Passkey Registered"),
|
||||
("passkey_removed", "Passkey Removed"),
|
||||
("passkey_login", "Passkey Login"),
|
||||
("social_linked", "Social Account Linked"),
|
||||
("social_unlinked", "Social Account Unlinked"),
|
||||
("password_reset_requested", "Password Reset Requested"),
|
||||
("password_reset_completed", "Password Reset Completed"),
|
||||
("password_changed", "Password Changed"),
|
||||
("session_invalidated", "Session Invalidated"),
|
||||
("recovery_code_used", "Recovery Code Used"),
|
||||
("recovery_codes_regenerated", "Recovery Codes Regenerated"),
|
||||
],
|
||||
db_index=True,
|
||||
domain="accounts",
|
||||
help_text="Type of security event",
|
||||
max_length=50,
|
||||
),
|
||||
),
|
||||
("ip_address", models.GenericIPAddressField(help_text="IP address of the request")),
|
||||
("user_agent", models.TextField(blank=True, help_text="User agent string from the request")),
|
||||
("metadata", models.JSONField(blank=True, default=dict, help_text="Additional event-specific data")),
|
||||
("created_at", models.DateTimeField(auto_now_add=True, help_text="When this event occurred")),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User this event is associated with",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="security_logs",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Security Log",
|
||||
"verbose_name_plural": "Security Logs",
|
||||
"ordering": ["-created_at"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="SecurityLogEvent",
|
||||
fields=[
|
||||
("pgh_id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("pgh_created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("pgh_label", models.TextField(help_text="The event label.")),
|
||||
("id", models.BigIntegerField()),
|
||||
(
|
||||
"event_type",
|
||||
apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
choice_group="security_event_types",
|
||||
choices=[
|
||||
("login_success", "Login Success"),
|
||||
("login_failed", "Login Failed"),
|
||||
("logout", "Logout"),
|
||||
("mfa_enrolled", "MFA Enrolled"),
|
||||
("mfa_disabled", "MFA Disabled"),
|
||||
("mfa_challenge_success", "MFA Challenge Success"),
|
||||
("mfa_challenge_failed", "MFA Challenge Failed"),
|
||||
("passkey_registered", "Passkey Registered"),
|
||||
("passkey_removed", "Passkey Removed"),
|
||||
("passkey_login", "Passkey Login"),
|
||||
("social_linked", "Social Account Linked"),
|
||||
("social_unlinked", "Social Account Unlinked"),
|
||||
("password_reset_requested", "Password Reset Requested"),
|
||||
("password_reset_completed", "Password Reset Completed"),
|
||||
("password_changed", "Password Changed"),
|
||||
("session_invalidated", "Session Invalidated"),
|
||||
("recovery_code_used", "Recovery Code Used"),
|
||||
("recovery_codes_regenerated", "Recovery Codes Regenerated"),
|
||||
],
|
||||
domain="accounts",
|
||||
help_text="Type of security event",
|
||||
max_length=50,
|
||||
),
|
||||
),
|
||||
("ip_address", models.GenericIPAddressField(help_text="IP address of the request")),
|
||||
("user_agent", models.TextField(blank=True, help_text="User agent string from the request")),
|
||||
("metadata", models.JSONField(blank=True, default=dict, help_text="Additional event-specific data")),
|
||||
("created_at", models.DateTimeField(auto_now_add=True, help_text="When this event occurred")),
|
||||
(
|
||||
"pgh_context",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
to="pghistory.context",
|
||||
),
|
||||
),
|
||||
(
|
||||
"pgh_obj",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="events",
|
||||
to="accounts.securitylog",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
db_constraint=False,
|
||||
help_text="User this event is associated with",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="securitylog",
|
||||
index=models.Index(fields=["user", "-created_at"], name="accounts_se_user_id_d46023_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="securitylog",
|
||||
index=models.Index(fields=["event_type", "-created_at"], name="accounts_se_event_t_814971_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="securitylog",
|
||||
index=models.Index(fields=["ip_address", "-created_at"], name="accounts_se_ip_addr_2a19c8_idx"),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="securitylog",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "accounts_securitylogevent" ("created_at", "event_type", "id", "ip_address", "metadata", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "user_agent", "user_id") VALUES (NEW."created_at", NEW."event_type", NEW."id", NEW."ip_address", NEW."metadata", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."user_agent", NEW."user_id"); RETURN NULL;',
|
||||
hash="a40cf3f6fa9e8cda99f7204edb226b26bbe03eda",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_5d4cf",
|
||||
table="accounts_securitylog",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="securitylog",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "accounts_securitylogevent" ("created_at", "event_type", "id", "ip_address", "metadata", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "user_agent", "user_id") VALUES (NEW."created_at", NEW."event_type", NEW."id", NEW."ip_address", NEW."metadata", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."user_agent", NEW."user_id"); RETURN NULL;',
|
||||
hash="244fc44bdaff1bf2d557f09ae452a9ea77274068",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_d4645",
|
||||
table="accounts_securitylog",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user