mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-01-02 01:47:04 -05:00
feat: Implement initial schema and add various API, service, and management command enhancements across the application.
This commit is contained in:
@@ -28,27 +28,16 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
def setUpTestData(cls):
|
||||
"""Set up test data for all tests in this class."""
|
||||
# Create regular user
|
||||
cls.user = User.objects.create_user(
|
||||
username="testuser",
|
||||
email="testuser@example.com",
|
||||
password="testpass123"
|
||||
)
|
||||
cls.user = User.objects.create_user(username="testuser", email="testuser@example.com", password="testpass123")
|
||||
|
||||
# Create moderator user
|
||||
cls.moderator = User.objects.create_user(
|
||||
username="moderator",
|
||||
email="moderator@example.com",
|
||||
password="modpass123",
|
||||
is_staff=True
|
||||
username="moderator", email="moderator@example.com", password="modpass123", is_staff=True
|
||||
)
|
||||
|
||||
# Create admin user
|
||||
cls.admin = User.objects.create_user(
|
||||
username="admin",
|
||||
email="admin@example.com",
|
||||
password="adminpass123",
|
||||
is_staff=True,
|
||||
is_superuser=True
|
||||
username="admin", email="admin@example.com", password="adminpass123", is_staff=True, is_superuser=True
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
@@ -76,7 +65,7 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
submission_type="EDIT",
|
||||
changes={"description": "Test change"},
|
||||
reason="Integration test",
|
||||
status="PENDING"
|
||||
status="PENDING",
|
||||
)
|
||||
|
||||
url = reverse(
|
||||
@@ -85,15 +74,12 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
"app_label": "moderation",
|
||||
"model_name": "editsubmission",
|
||||
"pk": submission.pk,
|
||||
"transition_name": "transition_to_approved"
|
||||
}
|
||||
"transition_name": "transition_to_approved",
|
||||
},
|
||||
)
|
||||
|
||||
# Make request with HTMX header
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
# Should return 200 OK
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -129,7 +115,7 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
submission_type="EDIT",
|
||||
changes={"description": "Test change non-htmx"},
|
||||
reason="Integration test non-htmx",
|
||||
status="PENDING"
|
||||
status="PENDING",
|
||||
)
|
||||
|
||||
url = reverse(
|
||||
@@ -138,8 +124,8 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
"app_label": "moderation",
|
||||
"model_name": "editsubmission",
|
||||
"pk": submission.pk,
|
||||
"transition_name": "transition_to_approved"
|
||||
}
|
||||
"transition_name": "transition_to_approved",
|
||||
},
|
||||
)
|
||||
|
||||
# Make request WITHOUT HTMX header
|
||||
@@ -177,7 +163,7 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
submission_type="EDIT",
|
||||
changes={"description": "Test partial"},
|
||||
reason="Partial test",
|
||||
status="PENDING"
|
||||
status="PENDING",
|
||||
)
|
||||
|
||||
url = reverse(
|
||||
@@ -186,14 +172,11 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
"app_label": "moderation",
|
||||
"model_name": "editsubmission",
|
||||
"pk": submission.pk,
|
||||
"transition_name": "transition_to_approved"
|
||||
}
|
||||
"transition_name": "transition_to_approved",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
# Response should contain HTML (partial template)
|
||||
self.assertIn("text/html", response["Content-Type"])
|
||||
@@ -217,14 +200,11 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
"app_label": "parks",
|
||||
"model_name": "park",
|
||||
"pk": park.pk,
|
||||
"transition_name": "transition_to_closed_temp"
|
||||
}
|
||||
"transition_name": "transition_to_closed_temp",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
# Parse HX-Trigger header
|
||||
trigger_data = json.loads(response["HX-Trigger"])
|
||||
@@ -249,14 +229,11 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
"app_label": "nonexistent",
|
||||
"model_name": "fakemodel",
|
||||
"pk": 1,
|
||||
"transition_name": "fake_transition"
|
||||
}
|
||||
"transition_name": "fake_transition",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
# Should return 404
|
||||
self.assertEqual(response.status_code, 404)
|
||||
@@ -282,14 +259,11 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
"app_label": "parks",
|
||||
"model_name": "park",
|
||||
"pk": park.pk,
|
||||
"transition_name": "nonexistent_transition"
|
||||
}
|
||||
"transition_name": "nonexistent_transition",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
# Should return 400 Bad Request
|
||||
self.assertEqual(response.status_code, 400)
|
||||
@@ -320,7 +294,7 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
submission_type="EDIT",
|
||||
changes={"description": "Permission test"},
|
||||
reason="Permission test",
|
||||
status="PENDING"
|
||||
status="PENDING",
|
||||
)
|
||||
|
||||
url = reverse(
|
||||
@@ -329,14 +303,11 @@ class TestFSMTransitionViewHTMX(TestCase):
|
||||
"app_label": "moderation",
|
||||
"model_name": "editsubmission",
|
||||
"pk": submission.pk,
|
||||
"transition_name": "transition_to_approved"
|
||||
}
|
||||
"transition_name": "transition_to_approved",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
# Should return 400 or 403 (permission denied)
|
||||
self.assertIn(response.status_code, [400, 403])
|
||||
@@ -355,10 +326,7 @@ class TestFSMTransitionViewParkModel(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.moderator = User.objects.create_user(
|
||||
username="mod_park",
|
||||
email="mod_park@example.com",
|
||||
password="modpass123",
|
||||
is_staff=True
|
||||
username="mod_park", email="mod_park@example.com", password="modpass123", is_staff=True
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
@@ -379,14 +347,11 @@ class TestFSMTransitionViewParkModel(TestCase):
|
||||
"app_label": "parks",
|
||||
"model_name": "park",
|
||||
"pk": park.pk,
|
||||
"transition_name": "transition_to_closed_temp"
|
||||
}
|
||||
"transition_name": "transition_to_closed_temp",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -416,14 +381,11 @@ class TestFSMTransitionViewParkModel(TestCase):
|
||||
"app_label": "parks",
|
||||
"model_name": "park",
|
||||
"pk": park.pk,
|
||||
"transition_name": "transition_to_operating"
|
||||
}
|
||||
"transition_name": "transition_to_operating",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -445,14 +407,11 @@ class TestFSMTransitionViewParkModel(TestCase):
|
||||
"app_label": "parks",
|
||||
"model_name": "park",
|
||||
"slug": park.slug,
|
||||
"transition_name": "transition_to_closed_temp"
|
||||
}
|
||||
"transition_name": "transition_to_closed_temp",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -471,10 +430,7 @@ class TestFSMTransitionViewRideModel(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.moderator = User.objects.create_user(
|
||||
username="mod_ride",
|
||||
email="mod_ride@example.com",
|
||||
password="modpass123",
|
||||
is_staff=True
|
||||
username="mod_ride", email="mod_ride@example.com", password="modpass123", is_staff=True
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
@@ -495,14 +451,11 @@ class TestFSMTransitionViewRideModel(TestCase):
|
||||
"app_label": "rides",
|
||||
"model_name": "ride",
|
||||
"pk": ride.pk,
|
||||
"transition_name": "transition_to_closed_temp"
|
||||
}
|
||||
"transition_name": "transition_to_closed_temp",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -524,18 +477,10 @@ class TestFSMTransitionViewRideModel(TestCase):
|
||||
|
||||
url = reverse(
|
||||
"core:fsm_transition",
|
||||
kwargs={
|
||||
"app_label": "rides",
|
||||
"model_name": "ride",
|
||||
"pk": ride.pk,
|
||||
"transition_name": "transition_to_sbno"
|
||||
}
|
||||
kwargs={"app_label": "rides", "model_name": "ride", "pk": ride.pk, "transition_name": "transition_to_sbno"},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -553,17 +498,10 @@ class TestFSMTransitionViewModerationModels(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = User.objects.create_user(
|
||||
username="submitter",
|
||||
email="submitter@example.com",
|
||||
password="testpass123"
|
||||
)
|
||||
cls.user = User.objects.create_user(username="submitter", email="submitter@example.com", password="testpass123")
|
||||
|
||||
cls.moderator = User.objects.create_user(
|
||||
username="mod_moderation",
|
||||
email="mod_moderation@example.com",
|
||||
password="modpass123",
|
||||
is_staff=True
|
||||
username="mod_moderation", email="mod_moderation@example.com", password="modpass123", is_staff=True
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
@@ -588,7 +526,7 @@ class TestFSMTransitionViewModerationModels(TestCase):
|
||||
submission_type="EDIT",
|
||||
changes={"description": "Approve test"},
|
||||
reason="Approve test",
|
||||
status="PENDING"
|
||||
status="PENDING",
|
||||
)
|
||||
|
||||
url = reverse(
|
||||
@@ -597,14 +535,11 @@ class TestFSMTransitionViewModerationModels(TestCase):
|
||||
"app_label": "moderation",
|
||||
"model_name": "editsubmission",
|
||||
"pk": submission.pk,
|
||||
"transition_name": "transition_to_approved"
|
||||
}
|
||||
"transition_name": "transition_to_approved",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -633,7 +568,7 @@ class TestFSMTransitionViewModerationModels(TestCase):
|
||||
submission_type="EDIT",
|
||||
changes={"description": "Reject test"},
|
||||
reason="Reject test",
|
||||
status="PENDING"
|
||||
status="PENDING",
|
||||
)
|
||||
|
||||
url = reverse(
|
||||
@@ -642,14 +577,11 @@ class TestFSMTransitionViewModerationModels(TestCase):
|
||||
"app_label": "moderation",
|
||||
"model_name": "editsubmission",
|
||||
"pk": submission.pk,
|
||||
"transition_name": "transition_to_rejected"
|
||||
}
|
||||
"transition_name": "transition_to_rejected",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -678,7 +610,7 @@ class TestFSMTransitionViewModerationModels(TestCase):
|
||||
submission_type="EDIT",
|
||||
changes={"description": "Escalate test"},
|
||||
reason="Escalate test",
|
||||
status="PENDING"
|
||||
status="PENDING",
|
||||
)
|
||||
|
||||
url = reverse(
|
||||
@@ -687,14 +619,11 @@ class TestFSMTransitionViewModerationModels(TestCase):
|
||||
"app_label": "moderation",
|
||||
"model_name": "editsubmission",
|
||||
"pk": submission.pk,
|
||||
"transition_name": "transition_to_escalated"
|
||||
}
|
||||
"transition_name": "transition_to_escalated",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
response = self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -712,16 +641,11 @@ class TestFSMTransitionViewStateLog(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = User.objects.create_user(
|
||||
username="submitter_log",
|
||||
email="submitter_log@example.com",
|
||||
password="testpass123"
|
||||
username="submitter_log", email="submitter_log@example.com", password="testpass123"
|
||||
)
|
||||
|
||||
cls.moderator = User.objects.create_user(
|
||||
username="mod_log",
|
||||
email="mod_log@example.com",
|
||||
password="modpass123",
|
||||
is_staff=True
|
||||
username="mod_log", email="mod_log@example.com", password="modpass123", is_staff=True
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
@@ -748,13 +672,12 @@ class TestFSMTransitionViewStateLog(TestCase):
|
||||
submission_type="EDIT",
|
||||
changes={"description": "StateLog test"},
|
||||
reason="StateLog test",
|
||||
status="PENDING"
|
||||
status="PENDING",
|
||||
)
|
||||
|
||||
# Count existing StateLog entries
|
||||
initial_log_count = StateLog.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(EditSubmission),
|
||||
object_id=submission.pk
|
||||
content_type=ContentType.objects.get_for_model(EditSubmission), object_id=submission.pk
|
||||
).count()
|
||||
|
||||
url = reverse(
|
||||
@@ -763,28 +686,23 @@ class TestFSMTransitionViewStateLog(TestCase):
|
||||
"app_label": "moderation",
|
||||
"model_name": "editsubmission",
|
||||
"pk": submission.pk,
|
||||
"transition_name": "transition_to_approved"
|
||||
}
|
||||
"transition_name": "transition_to_approved",
|
||||
},
|
||||
)
|
||||
|
||||
self.client.post(
|
||||
url,
|
||||
HTTP_HX_REQUEST="true"
|
||||
)
|
||||
self.client.post(url, HTTP_HX_REQUEST="true")
|
||||
|
||||
# Check that a new StateLog entry was created
|
||||
new_log_count = StateLog.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(EditSubmission),
|
||||
object_id=submission.pk
|
||||
content_type=ContentType.objects.get_for_model(EditSubmission), object_id=submission.pk
|
||||
).count()
|
||||
|
||||
self.assertEqual(new_log_count, initial_log_count + 1)
|
||||
|
||||
# Verify the StateLog entry details
|
||||
latest_log = StateLog.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(EditSubmission),
|
||||
object_id=submission.pk
|
||||
).latest('timestamp')
|
||||
content_type=ContentType.objects.get_for_model(EditSubmission), object_id=submission.pk
|
||||
).latest("timestamp")
|
||||
|
||||
self.assertEqual(latest_log.state, "APPROVED")
|
||||
self.assertEqual(latest_log.by, self.moderator)
|
||||
|
||||
@@ -9,6 +9,7 @@ from datetime import date, timedelta
|
||||
|
||||
import pytest
|
||||
from django.test import TestCase
|
||||
from django_fsm import TransitionNotAllowed
|
||||
|
||||
from tests.factories import (
|
||||
ParkAreaFactory,
|
||||
@@ -55,7 +56,7 @@ class TestParkFSMTransitions(TestCase):
|
||||
user = UserFactory()
|
||||
|
||||
# This should fail - can't reopen permanently closed park
|
||||
with pytest.raises(Exception):
|
||||
with pytest.raises((TransitionNotAllowed, ValueError)):
|
||||
park.open(user=user)
|
||||
|
||||
|
||||
|
||||
@@ -138,9 +138,7 @@ class TestParkReviewWorkflow(TestCase):
|
||||
ParkReviewFactory(park=park, user=user2, rating=10, is_published=True)
|
||||
|
||||
# Calculate average
|
||||
avg = park.reviews.filter(is_published=True).values_list(
|
||||
"rating", flat=True
|
||||
)
|
||||
avg = park.reviews.filter(is_published=True).values_list("rating", flat=True)
|
||||
calculated_avg = sum(avg) / len(avg)
|
||||
|
||||
assert calculated_avg == 9.0
|
||||
|
||||
@@ -31,9 +31,7 @@ class TestParkPhotoUploadWorkflow(TestCase):
|
||||
@patch("apps.parks.services.media_service.MediaService.process_image")
|
||||
@patch("apps.parks.services.media_service.MediaService.generate_default_caption")
|
||||
@patch("apps.parks.services.media_service.MediaService.extract_exif_date")
|
||||
def test__upload_photo__creates_pending_photo(
|
||||
self, mock_exif, mock_caption, mock_process, mock_validate
|
||||
):
|
||||
def test__upload_photo__creates_pending_photo(self, mock_exif, mock_caption, mock_process, mock_validate):
|
||||
"""Test uploading photo creates a pending photo."""
|
||||
mock_validate.return_value = (True, None)
|
||||
mock_process.return_value = Mock()
|
||||
|
||||
Reference in New Issue
Block a user