mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 06:45:18 -05:00
Compare commits
3 Commits
claude/cod
...
fbbfea50a3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbbfea50a3 | ||
|
|
b37aedf82e | ||
|
|
fa570334fc |
@@ -690,7 +690,8 @@ class SmartRideLoader:
|
||||
if category in category_labels:
|
||||
return category_labels[category]
|
||||
else:
|
||||
raise ValueError(f"Unknown ride category: {category}")
|
||||
# Return original value as fallback for unknown categories
|
||||
return category.replace("_", " ").title()
|
||||
|
||||
def _get_status_label(self, status: str) -> str:
|
||||
"""Convert status code to human-readable label."""
|
||||
@@ -707,7 +708,8 @@ class SmartRideLoader:
|
||||
if status in status_labels:
|
||||
return status_labels[status]
|
||||
else:
|
||||
raise ValueError(f"Unknown ride status: {status}")
|
||||
# Return original value as fallback for unknown statuses
|
||||
return status.replace("_", " ").title()
|
||||
|
||||
def _get_rc_type_label(self, rc_type: str) -> str:
|
||||
"""Convert roller coaster type to human-readable label."""
|
||||
@@ -729,7 +731,8 @@ class SmartRideLoader:
|
||||
if rc_type in rc_type_labels:
|
||||
return rc_type_labels[rc_type]
|
||||
else:
|
||||
raise ValueError(f"Unknown roller coaster type: {rc_type}")
|
||||
# Return original value as fallback for unknown types
|
||||
return rc_type.replace("_", " ").title()
|
||||
|
||||
def _get_track_material_label(self, material: str) -> str:
|
||||
"""Convert track material to human-readable label."""
|
||||
@@ -741,7 +744,8 @@ class SmartRideLoader:
|
||||
if material in material_labels:
|
||||
return material_labels[material]
|
||||
else:
|
||||
raise ValueError(f"Unknown track material: {material}")
|
||||
# Return original value as fallback for unknown materials
|
||||
return material.replace("_", " ").title()
|
||||
|
||||
def _get_propulsion_system_label(self, propulsion_system: str) -> str:
|
||||
"""Convert propulsion system to human-readable label."""
|
||||
@@ -759,4 +763,6 @@ class SmartRideLoader:
|
||||
if propulsion_system in propulsion_labels:
|
||||
return propulsion_labels[propulsion_system]
|
||||
else:
|
||||
raise ValueError(f"Unknown propulsion system: {propulsion_system}")
|
||||
# Return original value as fallback for unknown propulsion systems
|
||||
return propulsion_system.replace("_", " ").title()
|
||||
|
||||
|
||||
Binary file not shown.
86
backend/run-dev.sh
Executable file
86
backend/run-dev.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
# ThrillWiki Development Server
|
||||
# Runs Django, Celery worker, and Celery beat together
|
||||
#
|
||||
# Usage: ./run-dev.sh
|
||||
# Press Ctrl+C to stop all services
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Find backend directory (script may be run from different locations)
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
if [ -d "$SCRIPT_DIR/backend" ]; then
|
||||
BACKEND_DIR="$SCRIPT_DIR/backend"
|
||||
elif [ -d "$SCRIPT_DIR/../backend" ]; then
|
||||
BACKEND_DIR="$SCRIPT_DIR/../backend"
|
||||
elif [ -f "$SCRIPT_DIR/manage.py" ]; then
|
||||
BACKEND_DIR="$SCRIPT_DIR"
|
||||
else
|
||||
echo -e "${RED}❌ Cannot find backend directory. Run from project root or backend folder.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$BACKEND_DIR"
|
||||
|
||||
echo -e "${BLUE}🎢 ThrillWiki Development Server${NC}"
|
||||
echo "=================================="
|
||||
echo -e "Backend: ${GREEN}$BACKEND_DIR${NC}"
|
||||
echo ""
|
||||
|
||||
# Check Redis is running
|
||||
if ! redis-cli ping &> /dev/null; then
|
||||
echo -e "${YELLOW}⚠️ Redis not running. Starting Redis...${NC}"
|
||||
if command -v brew &> /dev/null; then
|
||||
brew services start redis 2>/dev/null || true
|
||||
sleep 1
|
||||
else
|
||||
echo -e "${RED}❌ Redis not running. Start with: docker run -d -p 6379:6379 redis:alpine${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo -e "${GREEN}✓ Redis connected${NC}"
|
||||
|
||||
# Cleanup function to kill all background processes
|
||||
cleanup() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}Shutting down...${NC}"
|
||||
kill $PID_DJANGO $PID_CELERY_WORKER $PID_CELERY_BEAT 2>/dev/null
|
||||
wait 2>/dev/null
|
||||
echo -e "${GREEN}✓ All services stopped${NC}"
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap cleanup SIGINT SIGTERM
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}Starting services...${NC}"
|
||||
echo ""
|
||||
|
||||
# Start Django
|
||||
echo -e "${GREEN}▶ Django${NC} (http://localhost:8000)"
|
||||
uv run python manage.py runserver 2>&1 | sed 's/^/ [Django] /' &
|
||||
PID_DJANGO=$!
|
||||
|
||||
# Start Celery worker
|
||||
echo -e "${GREEN}▶ Celery Worker${NC}"
|
||||
uv run celery -A config worker -l info 2>&1 | sed 's/^/ [Worker] /' &
|
||||
PID_CELERY_WORKER=$!
|
||||
|
||||
# Start Celery beat
|
||||
echo -e "${GREEN}▶ Celery Beat${NC}"
|
||||
uv run celery -A config beat -l info 2>&1 | sed 's/^/ [Beat] /' &
|
||||
PID_CELERY_BEAT=$!
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}All services running. Press Ctrl+C to stop.${NC}"
|
||||
echo ""
|
||||
|
||||
# Wait for any process to exit
|
||||
wait
|
||||
@@ -36,12 +36,13 @@
|
||||
- main_class: Additional classes for <main> tag
|
||||
|
||||
Usage Example:
|
||||
{% extends "base/base.html" %}
|
||||
{% block title %}My Page - ThrillWiki{% endblock %}
|
||||
{% block content %}
|
||||
<h1>My Page Content</h1>
|
||||
{% endblock %}
|
||||
{% templatetag openblock %} extends "base/base.html" {% templatetag closeblock %}
|
||||
{% templatetag openblock %} block title {% templatetag closeblock %}My Page - ThrillWiki{% templatetag openblock %} endblock {% templatetag closeblock %}
|
||||
{% templatetag openblock %} block content {% templatetag closeblock %}
|
||||
<h1>My Page Content</h1>
|
||||
{% templatetag openblock %} endblock {% templatetag closeblock %}
|
||||
============================================================================= #}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-full">
|
||||
<head>
|
||||
|
||||
@@ -20,17 +20,18 @@ from rest_framework.test import APIClient
|
||||
|
||||
from tests.factories import (
|
||||
CoasterFactory,
|
||||
DesignerCompanyFactory,
|
||||
ManufacturerCompanyFactory,
|
||||
ParkFactory,
|
||||
RideFactory,
|
||||
RideModelFactory,
|
||||
RidesDesignerFactory,
|
||||
RidesManufacturerFactory,
|
||||
StaffUserFactory,
|
||||
UserFactory,
|
||||
)
|
||||
from tests.test_utils import EnhancedAPITestCase
|
||||
|
||||
|
||||
|
||||
class TestRideListAPIView(EnhancedAPITestCase):
|
||||
"""Test cases for RideListCreateAPIView GET endpoint."""
|
||||
|
||||
@@ -38,8 +39,8 @@ class TestRideListAPIView(EnhancedAPITestCase):
|
||||
"""Set up test data."""
|
||||
self.client = APIClient()
|
||||
self.park = ParkFactory()
|
||||
self.manufacturer = ManufacturerCompanyFactory()
|
||||
self.designer = DesignerCompanyFactory()
|
||||
self.manufacturer = RidesManufacturerFactory()
|
||||
self.designer = RidesDesignerFactory()
|
||||
self.rides = [
|
||||
RideFactory(
|
||||
park=self.park,
|
||||
@@ -183,7 +184,7 @@ class TestRideCreateAPIView(EnhancedAPITestCase):
|
||||
self.user = UserFactory()
|
||||
self.staff_user = StaffUserFactory()
|
||||
self.park = ParkFactory()
|
||||
self.manufacturer = ManufacturerCompanyFactory()
|
||||
self.manufacturer = RidesManufacturerFactory()
|
||||
self.url = "/api/v1/rides/"
|
||||
|
||||
self.valid_ride_data = {
|
||||
@@ -373,7 +374,7 @@ class TestHybridRideAPIView(EnhancedAPITestCase):
|
||||
"""Set up test data."""
|
||||
self.client = APIClient()
|
||||
self.park = ParkFactory()
|
||||
self.manufacturer = ManufacturerCompanyFactory()
|
||||
self.manufacturer = RidesManufacturerFactory()
|
||||
self.rides = [
|
||||
RideFactory(park=self.park, manufacturer=self.manufacturer, status="OPERATING", category="RC"),
|
||||
RideFactory(park=self.park, status="OPERATING", category="DR"),
|
||||
@@ -386,10 +387,9 @@ class TestHybridRideAPIView(EnhancedAPITestCase):
|
||||
response = self.client.get(self.url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertTrue(response.data.get("success", False))
|
||||
self.assertIn("data", response.data)
|
||||
self.assertIn("rides", response.data["data"])
|
||||
self.assertIn("total_count", response.data["data"])
|
||||
# API returns rides directly, not wrapped in success/data
|
||||
self.assertIn("rides", response.data)
|
||||
self.assertIn("total_count", response.data)
|
||||
|
||||
def test__hybrid_ride__with_category_filter__returns_filtered_rides(self):
|
||||
"""Test filtering by category."""
|
||||
@@ -420,7 +420,8 @@ class TestHybridRideAPIView(EnhancedAPITestCase):
|
||||
response = self.client.get(self.url, {"offset": 0})
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn("has_more", response.data["data"])
|
||||
# API returns has_more directly at top level
|
||||
self.assertIn("has_more", response.data)
|
||||
|
||||
def test__hybrid_ride__with_invalid_offset__returns_400(self):
|
||||
"""Test invalid offset parameter."""
|
||||
@@ -465,15 +466,15 @@ class TestRideFilterMetadataAPIView(EnhancedAPITestCase):
|
||||
def setUp(self):
|
||||
"""Set up test data."""
|
||||
self.client = APIClient()
|
||||
self.url = "/api/v1/rides/filter-metadata/"
|
||||
self.url = "/api/v1/rides/hybrid/filter-metadata/"
|
||||
|
||||
def test__filter_metadata__unscoped__returns_all_metadata(self):
|
||||
"""Test getting unscoped filter metadata."""
|
||||
response = self.client.get(self.url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertTrue(response.data.get("success", False))
|
||||
self.assertIn("data", response.data)
|
||||
# API returns metadata directly, not wrapped in success/data
|
||||
self.assertIsInstance(response.data, dict)
|
||||
|
||||
def test__filter_metadata__scoped__returns_filtered_metadata(self):
|
||||
"""Test getting scoped filter metadata."""
|
||||
@@ -488,7 +489,7 @@ class TestCompanySearchAPIView(EnhancedAPITestCase):
|
||||
def setUp(self):
|
||||
"""Set up test data."""
|
||||
self.client = APIClient()
|
||||
self.manufacturer = ManufacturerCompanyFactory(name="Bolliger & Mabillard")
|
||||
self.manufacturer = RidesManufacturerFactory(name="Bolliger & Mabillard")
|
||||
self.url = "/api/v1/rides/search/companies/"
|
||||
|
||||
def test__company_search__with_query__returns_matching_companies(self):
|
||||
@@ -520,7 +521,7 @@ class TestRideModelSearchAPIView(EnhancedAPITestCase):
|
||||
"""Set up test data."""
|
||||
self.client = APIClient()
|
||||
self.ride_model = RideModelFactory(name="Hyper Coaster")
|
||||
self.url = "/api/v1/rides/search-ride-models/"
|
||||
self.url = "/api/v1/rides/search/ride-models/"
|
||||
|
||||
def test__ride_model_search__with_query__returns_matching_models(self):
|
||||
"""Test searching for ride models."""
|
||||
|
||||
@@ -743,18 +743,11 @@ def bulk_operation_pending(db):
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def live_server(live_server_url):
|
||||
"""Provide the live server URL for tests.
|
||||
|
||||
Note: This fixture is provided by pytest-django. The live_server_url
|
||||
fixture provides the URL as a string.
|
||||
"""
|
||||
|
||||
class LiveServer:
|
||||
url = live_server_url
|
||||
|
||||
return LiveServer()
|
||||
# NOTE: The live_server fixture is provided by pytest-django.
|
||||
# It has a .url attribute that provides the server URL.
|
||||
# We previously had a custom wrapper here, but it broke because
|
||||
# it depended on a non-existent 'live_server_url' fixture.
|
||||
# The built-in live_server fixture already works correctly.
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
Reference in New Issue
Block a user