mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 13:15:17 -05:00
Based on the git diff provided, here's a concise and descriptive commit message:
feat: add passkey authentication and enhance user preferences - Add passkey login security event type with fingerprint icon - Include request and site context in email confirmation for backend - Add user_id exact match filter to prevent incorrect user lookups - Enable PATCH method for updating user preferences via API - Add moderation_preferences support to user settings - Optimize ticket queries with select_related and prefetch_related This commit introduces passkey authentication tracking, improves user profile filtering accuracy, and extends the preferences API to support updates. Query optimizations reduce database hits for ticket listings.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# Generated by Django 5.2.10 on 2026-01-11 18:06
|
||||
|
||||
import apps.core.choices.fields
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("moderation", "0009_add_claim_fields"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="ModerationAuditLog",
|
||||
fields=[
|
||||
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
(
|
||||
"action",
|
||||
apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
choice_group="moderation_audit_actions",
|
||||
choices=[
|
||||
("approved", "Approved"),
|
||||
("rejected", "Rejected"),
|
||||
("claimed", "Claimed"),
|
||||
("unclaimed", "Unclaimed"),
|
||||
("escalated", "Escalated"),
|
||||
("converted_to_edit", "Converted to Edit"),
|
||||
("status_changed", "Status Changed"),
|
||||
("notes_added", "Notes Added"),
|
||||
("auto_approved", "Auto Approved"),
|
||||
],
|
||||
db_index=True,
|
||||
domain="moderation",
|
||||
help_text="The action that was performed",
|
||||
max_length=50,
|
||||
),
|
||||
),
|
||||
(
|
||||
"previous_status",
|
||||
models.CharField(blank=True, help_text="Status before the action", max_length=50, null=True),
|
||||
),
|
||||
(
|
||||
"new_status",
|
||||
models.CharField(blank=True, help_text="Status after the action", max_length=50, null=True),
|
||||
),
|
||||
("notes", models.TextField(blank=True, help_text="Notes or comments about the action", null=True)),
|
||||
(
|
||||
"is_system_action",
|
||||
models.BooleanField(
|
||||
db_index=True, default=False, help_text="Whether this was an automated system action"
|
||||
),
|
||||
),
|
||||
("is_test_data", models.BooleanField(default=False, help_text="Whether this is test data")),
|
||||
(
|
||||
"created_at",
|
||||
models.DateTimeField(auto_now_add=True, db_index=True, help_text="When this action was performed"),
|
||||
),
|
||||
(
|
||||
"moderator",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The moderator who performed the action (null for system actions)",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="moderation_audit_logs",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"submission",
|
||||
models.ForeignKey(
|
||||
help_text="The submission this audit log entry is for",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_logs",
|
||||
to="moderation.editsubmission",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Moderation Audit Log",
|
||||
"verbose_name_plural": "Moderation Audit Logs",
|
||||
"ordering": ["-created_at"],
|
||||
"indexes": [
|
||||
models.Index(fields=["submission", "created_at"], name="moderation__submiss_2f5e56_idx"),
|
||||
models.Index(fields=["moderator", "created_at"], name="moderation__moderat_591c14_idx"),
|
||||
models.Index(fields=["action", "created_at"], name="moderation__action_a98c47_idx"),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,99 @@
|
||||
# Generated by Django 5.2.10 on 2026-01-12 23:00
|
||||
|
||||
import django.db.models.deletion
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("django_cloudflareimages_toolkit", "0001_initial"),
|
||||
("moderation", "0010_moderationauditlog"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="editsubmission",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="editsubmission",
|
||||
name="update_update",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="editsubmission",
|
||||
name="caption",
|
||||
field=models.CharField(blank=True, help_text="Photo caption", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="editsubmission",
|
||||
name="date_taken",
|
||||
field=models.DateField(blank=True, help_text="Date the photo was taken", null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="editsubmission",
|
||||
name="photo",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Photo for photo submissions",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="django_cloudflareimages_toolkit.cloudflareimage",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="editsubmissionevent",
|
||||
name="caption",
|
||||
field=models.CharField(blank=True, help_text="Photo caption", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="editsubmissionevent",
|
||||
name="date_taken",
|
||||
field=models.DateField(blank=True, help_text="Date the photo was taken", null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="editsubmissionevent",
|
||||
name="photo",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
db_constraint=False,
|
||||
help_text="Photo for photo submissions",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="django_cloudflareimages_toolkit.cloudflareimage",
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="editsubmission",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "moderation_editsubmissionevent" ("caption", "changes", "claimed_at", "claimed_by_id", "content_type_id", "created_at", "date_taken", "handled_at", "handled_by_id", "id", "moderator_changes", "notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "photo_id", "reason", "source", "status", "submission_type", "updated_at", "user_id") VALUES (NEW."caption", NEW."changes", NEW."claimed_at", NEW."claimed_by_id", NEW."content_type_id", NEW."created_at", NEW."date_taken", NEW."handled_at", NEW."handled_by_id", NEW."id", NEW."moderator_changes", NEW."notes", NEW."object_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."photo_id", NEW."reason", NEW."source", NEW."status", NEW."submission_type", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="e9aed25fe6389b113919e729543a9abe20d9f30c",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_2c796",
|
||||
table="moderation_editsubmission",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="editsubmission",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "moderation_editsubmissionevent" ("caption", "changes", "claimed_at", "claimed_by_id", "content_type_id", "created_at", "date_taken", "handled_at", "handled_by_id", "id", "moderator_changes", "notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "photo_id", "reason", "source", "status", "submission_type", "updated_at", "user_id") VALUES (NEW."caption", NEW."changes", NEW."claimed_at", NEW."claimed_by_id", NEW."content_type_id", NEW."created_at", NEW."date_taken", NEW."handled_at", NEW."handled_by_id", NEW."id", NEW."moderator_changes", NEW."notes", NEW."object_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."photo_id", NEW."reason", NEW."source", NEW."status", NEW."submission_type", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="070083ba4d2d459067d9c3a90356a759f6262a90",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_ab38f",
|
||||
table="moderation_editsubmission",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
Data migration to copy PhotoSubmission data to EditSubmission.
|
||||
|
||||
This migration copies all PhotoSubmission rows to EditSubmission with submission_type="PHOTO".
|
||||
After this migration, PhotoSubmission model can be safely removed.
|
||||
"""
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def migrate_photo_submissions(apps, schema_editor):
|
||||
"""Copy PhotoSubmission data to EditSubmission."""
|
||||
PhotoSubmission = apps.get_model("moderation", "PhotoSubmission")
|
||||
EditSubmission = apps.get_model("moderation", "EditSubmission")
|
||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||
|
||||
# Get EditSubmission content type for reference
|
||||
edit_submission_ct = ContentType.objects.get_for_model(EditSubmission)
|
||||
|
||||
migrated = 0
|
||||
for photo_sub in PhotoSubmission.objects.all():
|
||||
# Create EditSubmission from PhotoSubmission
|
||||
EditSubmission.objects.create(
|
||||
user=photo_sub.user,
|
||||
content_type=photo_sub.content_type,
|
||||
object_id=photo_sub.object_id,
|
||||
submission_type="PHOTO",
|
||||
changes={}, # Photos don't have field changes
|
||||
reason="Photo submission", # Default reason
|
||||
status=photo_sub.status,
|
||||
created_at=photo_sub.created_at,
|
||||
handled_by=photo_sub.handled_by,
|
||||
handled_at=photo_sub.handled_at,
|
||||
notes=photo_sub.notes,
|
||||
claimed_by=photo_sub.claimed_by,
|
||||
claimed_at=photo_sub.claimed_at,
|
||||
# Photo-specific fields
|
||||
photo=photo_sub.photo,
|
||||
caption=photo_sub.caption,
|
||||
date_taken=photo_sub.date_taken,
|
||||
)
|
||||
migrated += 1
|
||||
|
||||
if migrated:
|
||||
print(f"Migrated {migrated} PhotoSubmission(s) to EditSubmission")
|
||||
|
||||
|
||||
def reverse_migration(apps, schema_editor):
|
||||
"""Remove migrated EditSubmissions with type PHOTO."""
|
||||
EditSubmission = apps.get_model("moderation", "EditSubmission")
|
||||
deleted, _ = EditSubmission.objects.filter(submission_type="PHOTO").delete()
|
||||
if deleted:
|
||||
print(f"Deleted {deleted} PHOTO EditSubmission(s)")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("moderation", "0011_add_photo_fields_to_editsubmission"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_photo_submissions, reverse_migration),
|
||||
]
|
||||
Reference in New Issue
Block a user