feat: Implement MFA authentication, add ride statistics model, and update various services, APIs, and tests across the application.

This commit is contained in:
pacnpal
2025-12-28 17:32:53 -05:00
parent aa56c46c27
commit c95f99ca10
452 changed files with 7948 additions and 6073 deletions

View File

@@ -6,6 +6,7 @@ def create_photo_permissions(sender, **kwargs):
"""Create custom permissions for domain-specific photo models"""
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from apps.parks.models import ParkPhoto
from apps.rides.models import RidePhoto

View File

@@ -1,9 +1,11 @@
import json
import requests
from django.core.files.base import ContentFile
from django.core.management.base import BaseCommand
from apps.parks.models import Park, ParkPhoto
from apps.rides.models import Ride, RidePhoto
import json
from django.core.files.base import ContentFile
class Command(BaseCommand):
@@ -13,7 +15,7 @@ class Command(BaseCommand):
self.stdout.write("Downloading photos from seed data...")
# Read seed data
with open("parks/management/commands/seed_data.json", "r") as f:
with open("parks/management/commands/seed_data.json") as f:
seed_data = json.load(f)
# Process parks and their photos

View File

@@ -1,8 +1,10 @@
import os
from django.core.management.base import BaseCommand
from django.db import transaction
from apps.parks.models import ParkPhoto
from apps.rides.models import RidePhoto
from django.db import transaction
class Command(BaseCommand):

View File

@@ -1,9 +1,11 @@
import os
import shutil
from django.conf import settings
from django.core.management.base import BaseCommand
from apps.parks.models import ParkPhoto
from apps.rides.models import RidePhoto
from django.conf import settings
import shutil
class Command(BaseCommand):
@@ -182,7 +184,7 @@ class Command(BaseCommand):
for content_type in ["park", "ride"]:
base_dir = os.path.join(settings.MEDIA_ROOT, content_type)
if os.path.exists(base_dir):
for root, dirs, files in os.walk(base_dir):
for root, _dirs, files in os.walk(base_dir):
for file in files:
file_path = os.path.join(root, file)
if file_path not in processed_files:

View File

@@ -1,14 +1,17 @@
from django.db import models
import pghistory
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from apps.core.history import TrackedModel
import pghistory
from django.db import models
# Using string reference for CloudflareImage to avoid circular imports if possible,
# or direct import if safe. django-cloudflare-images-toolkit usually provides a field or model.
# Checking installed apps... it's "django_cloudflareimages_toolkit".
from django_cloudflareimages_toolkit.models import CloudflareImage
from apps.core.history import TrackedModel
@pghistory.track()
class Photo(TrackedModel):
user = models.ForeignKey(
@@ -17,7 +20,7 @@ class Photo(TrackedModel):
related_name="photos",
help_text="User who uploaded this photo",
)
# The actual image
image = models.ForeignKey(
CloudflareImage,
@@ -38,10 +41,10 @@ class Photo(TrackedModel):
# Metadata
caption = models.CharField(max_length=255, blank=True, help_text="Photo caption")
is_public = models.BooleanField(
default=True,
default=True,
help_text="Whether this photo is visible to others"
)
# We might want credit/source info if not taken by user
source = models.CharField(max_length=100, blank=True, help_text="Source/Credit if applicable")

View File

@@ -1,12 +1,15 @@
from rest_framework import serializers
from .models import Photo
from apps.accounts.serializers import UserSerializer
from django_cloudflareimages_toolkit.models import CloudflareImage
from rest_framework import serializers
from apps.accounts.serializers import UserSerializer
from .models import Photo
# We need a serializer for the CloudflareImage model too if we want to show variants
class CloudflareImageSerializer(serializers.ModelSerializer):
variants = serializers.JSONField(read_only=True)
class Meta:
model = CloudflareImage
fields = ["id", "cloudflare_id", "variants"]
@@ -15,7 +18,7 @@ class PhotoSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
image = CloudflareImageSerializer(read_only=True)
cloudflare_image_id = serializers.CharField(write_only=True)
# Helper for frontend to get URLs easily
url = serializers.SerializerMethodField()
thumbnail = serializers.SerializerMethodField()
@@ -46,7 +49,7 @@ class PhotoSerializer(serializers.ModelSerializer):
# We assume it exists on CF side. We just need the DB record.
image, _ = CloudflareImage.objects.get_or_create(cloudflare_id=cloudflare_id)
validated_data["image"] = image
return super().create(validated_data)
def get_url(self, obj):

View File

@@ -1,5 +1,6 @@
from django.urls import path, include
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import PhotoViewSet
router = DefaultRouter()

View File

@@ -1,8 +1,11 @@
from rest_framework import viewsets, permissions, filters
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters, permissions, viewsets
from apps.core.permissions import IsOwnerOrReadOnly
from .models import Photo
from .serializers import PhotoSerializer
from apps.core.permissions import IsOwnerOrReadOnly
class PhotoViewSet(viewsets.ModelViewSet):
queryset = Photo.objects.filter(is_public=True)