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:
pacnpal
2026-01-12 19:13:05 -05:00
parent 2b66814d82
commit d631f3183c
56 changed files with 5860 additions and 264 deletions

View File

@@ -6,7 +6,7 @@ from django.utils import timezone
from apps.core.utils import capture_and_log
from .models import Ride
from .models import Ride, RideSubType
logger = logging.getLogger(__name__)
@@ -286,3 +286,59 @@ def track_ride_name_changes(sender, instance, **kwargs):
except Exception as e:
logger.exception(f"Failed to track name change for ride {instance.pk}: {e}")
# =============================================================================
# Auto-Create Ride Sub-Types on Ride Save
# =============================================================================
@receiver(post_save, sender=Ride)
def auto_create_ride_sub_type(sender, instance, created, **kwargs):
"""
Automatically create a RideSubType entry when a ride is saved with a new sub-type value.
This integrates with the submission pipeline - when a ride submission with a new
ride_sub_type value is approved, the sub-type automatically gets added to the
lookup table for future autocomplete suggestions.
Args:
sender: The Ride model class.
instance: The Ride instance that was saved.
created: Whether this is a new ride (not used, we check sub-types for all saves).
"""
# Skip if no ride_sub_type is set
if not instance.ride_sub_type or not instance.ride_sub_type.strip():
return
# Skip if no category is set (can't categorize the sub-type)
if not instance.category:
return
ride_sub_type_value = instance.ride_sub_type.strip()
try:
# Check if this sub-type already exists for this category
existing = RideSubType.objects.filter(
name__iexact=ride_sub_type_value,
category=instance.category
).exists()
if not existing:
# Create the new sub-type entry
RideSubType.objects.create(
name=ride_sub_type_value,
category=instance.category,
description=f"Auto-created from ride: {instance.name}",
created_by=getattr(instance, 'created_by', None),
)
logger.info(
f"Auto-created RideSubType '{ride_sub_type_value}' for category "
f"'{instance.category}' from ride '{instance.name}'"
)
except Exception as e:
# Non-critical error - log but don't fail the ride save
logger.warning(
f"Failed to auto-create RideSubType for ride {instance.pk}: {e}"
)