mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-30 08:27:00 -05:00
feat: Implement MFA authentication, add ride statistics model, and update various services, APIs, and tests across the application.
This commit is contained in:
@@ -8,15 +8,14 @@ The Company model is aliased as Operator to clarify its role as park operators,
|
||||
while maintaining backward compatibility through the Company alias.
|
||||
"""
|
||||
|
||||
from .parks import Park
|
||||
from .areas import ParkArea
|
||||
from .location import ParkLocation
|
||||
from .reviews import ParkReview
|
||||
from .companies import Company, CompanyHeadquarters
|
||||
from .media import ParkPhoto
|
||||
|
||||
# Import choices to trigger registration
|
||||
from ..choices import *
|
||||
from .areas import ParkArea
|
||||
from .companies import Company, CompanyHeadquarters
|
||||
from .location import ParkLocation
|
||||
from .media import ParkPhoto
|
||||
from .parks import Park
|
||||
from .reviews import ParkReview
|
||||
|
||||
# Alias Company as Operator for clarity
|
||||
Operator = Company
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import pghistory
|
||||
from django.db import models
|
||||
from django.utils.text import slugify
|
||||
import pghistory
|
||||
|
||||
from apps.core.history import TrackedModel
|
||||
|
||||
from .parks import Park
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import pghistory
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from django.utils.text import slugify
|
||||
from apps.core.models import TrackedModel
|
||||
|
||||
from apps.core.choices.fields import RichChoiceField
|
||||
import pghistory
|
||||
from apps.core.models import TrackedModel
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import pghistory
|
||||
from django.contrib.gis.db import models
|
||||
from django.contrib.gis.geos import Point
|
||||
import pghistory
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
|
||||
@@ -4,12 +4,14 @@ Park-specific media models for ThrillWiki.
|
||||
This module contains media models specific to parks domain.
|
||||
"""
|
||||
|
||||
from typing import Any, List, Optional, cast
|
||||
from django.db import models
|
||||
from typing import Any, cast
|
||||
|
||||
import pghistory
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
from apps.core.history import TrackedModel
|
||||
from apps.core.services.media_service import MediaService
|
||||
import pghistory
|
||||
|
||||
|
||||
def park_photo_upload_path(instance: models.Model, filename: str) -> str:
|
||||
@@ -114,7 +116,7 @@ class ParkPhoto(TrackedModel):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def file_size(self) -> Optional[int]:
|
||||
def file_size(self) -> int | None:
|
||||
"""Get file size in bytes."""
|
||||
try:
|
||||
return self.image.size
|
||||
@@ -122,7 +124,7 @@ class ParkPhoto(TrackedModel):
|
||||
return None
|
||||
|
||||
@property
|
||||
def dimensions(self) -> Optional[List[int]]:
|
||||
def dimensions(self) -> list[int] | None:
|
||||
"""Get image dimensions as [width, height]."""
|
||||
try:
|
||||
return [self.image.width, self.image.height]
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
import pghistory
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
from django.core.exceptions import ValidationError
|
||||
from config.django import base as settings
|
||||
from typing import Optional, Any, TYPE_CHECKING, List
|
||||
import pghistory
|
||||
from apps.core.history import TrackedModel
|
||||
from apps.core.choices import RichChoiceField
|
||||
from apps.core.state_machine import RichFSMField, StateMachineMixin
|
||||
|
||||
from apps.core.choices import RichChoiceField
|
||||
from apps.core.history import TrackedModel
|
||||
from apps.core.state_machine import RichFSMField, StateMachineMixin
|
||||
from config.django import base as settings
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from apps.rides.models import Ride
|
||||
from . import ParkArea
|
||||
from django.contrib.auth.models import AbstractBaseUser
|
||||
|
||||
from apps.rides.models import Ride
|
||||
|
||||
from . import ParkArea
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
class Park(StateMachineMixin, TrackedModel):
|
||||
@@ -57,6 +60,8 @@ class Park(StateMachineMixin, TrackedModel):
|
||||
max_digits=10, decimal_places=2, null=True, blank=True, help_text="Park size in acres"
|
||||
)
|
||||
website = models.URLField(blank=True, help_text="Official website URL")
|
||||
phone = models.CharField(max_length=30, blank=True, help_text="Contact phone number")
|
||||
email = models.EmailField(blank=True, help_text="Contact email address")
|
||||
|
||||
# Statistics
|
||||
average_rating = models.DecimalField(
|
||||
@@ -113,17 +118,17 @@ class Park(StateMachineMixin, TrackedModel):
|
||||
|
||||
# Computed fields for hybrid filtering
|
||||
opening_year = models.IntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
null=True,
|
||||
blank=True,
|
||||
db_index=True,
|
||||
help_text="Year the park opened (computed from opening_date)"
|
||||
)
|
||||
search_text = models.TextField(
|
||||
blank=True,
|
||||
blank=True,
|
||||
db_index=True,
|
||||
help_text="Searchable text combining name, description, location, and operator"
|
||||
)
|
||||
|
||||
|
||||
# Timezone for park operations
|
||||
timezone = models.CharField(
|
||||
max_length=50,
|
||||
@@ -220,6 +225,7 @@ class Park(StateMachineMixin, TrackedModel):
|
||||
|
||||
def save(self, *args: Any, **kwargs: Any) -> None:
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from apps.core.history import HistoricalSlug
|
||||
|
||||
# Get old instance if it exists
|
||||
@@ -264,13 +270,13 @@ class Park(StateMachineMixin, TrackedModel):
|
||||
self.opening_year = self.opening_date.year
|
||||
else:
|
||||
self.opening_year = None
|
||||
|
||||
|
||||
# Populate search_text for client-side filtering
|
||||
search_parts = [self.name]
|
||||
|
||||
|
||||
if self.description:
|
||||
search_parts.append(self.description)
|
||||
|
||||
|
||||
# Add location information if available
|
||||
try:
|
||||
if hasattr(self, 'location') and self.location:
|
||||
@@ -283,15 +289,15 @@ class Park(StateMachineMixin, TrackedModel):
|
||||
except Exception:
|
||||
# Handle case where location relationship doesn't exist yet
|
||||
pass
|
||||
|
||||
|
||||
# Add operator information
|
||||
if self.operator:
|
||||
search_parts.append(self.operator.name)
|
||||
|
||||
|
||||
# Add property owner information if different
|
||||
if self.property_owner and self.property_owner != self.operator:
|
||||
search_parts.append(self.property_owner.name)
|
||||
|
||||
|
||||
# Combine all parts into searchable text
|
||||
self.search_text = ' '.join(filter(None, search_parts)).lower()
|
||||
|
||||
@@ -315,7 +321,7 @@ class Park(StateMachineMixin, TrackedModel):
|
||||
return ""
|
||||
|
||||
@property
|
||||
def coordinates(self) -> Optional[List[float]]:
|
||||
def coordinates(self) -> list[float] | None:
|
||||
"""Returns coordinates as a list [latitude, longitude]"""
|
||||
if hasattr(self, "location") and self.location:
|
||||
coords = self.location.coordinates
|
||||
@@ -327,6 +333,7 @@ class Park(StateMachineMixin, TrackedModel):
|
||||
def get_by_slug(cls, slug: str) -> tuple["Park", bool]:
|
||||
"""Get park by current or historical slug"""
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from apps.core.history import HistoricalSlug
|
||||
|
||||
print(f"\nLooking up slug: {slug}")
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import pghistory
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
from django.db.models import functions
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
|
||||
from apps.core.history import TrackedModel
|
||||
import pghistory
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
|
||||
Reference in New Issue
Block a user