mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-23 11:51:09 -05:00
Add test utilities and state machine diagrams for FSM models
- Introduced reusable test utilities in `backend/tests/utils` for FSM transitions, HTMX interactions, and common scenarios. - Added factory functions for creating test submissions, parks, rides, and photo submissions. - Implemented assertion helpers for verifying state changes, toast notifications, and transition logs. - Created comprehensive state machine diagrams for all FSM-enabled models in `docs/STATE_DIAGRAMS.md`, detailing states, transitions, and guard conditions.
This commit is contained in:
@@ -7,6 +7,7 @@ moderation functionality including reports, queue management, actions, and bulk
|
||||
"""
|
||||
|
||||
from django.urls import path, include
|
||||
from django.views.generic import TemplateView
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from .views import (
|
||||
@@ -16,6 +17,49 @@ from .views import (
|
||||
BulkOperationViewSet,
|
||||
UserModerationViewSet,
|
||||
)
|
||||
from apps.core.views.views import FSMTransitionView
|
||||
|
||||
|
||||
class ModerationDashboardView(TemplateView):
|
||||
"""Moderation dashboard view with HTMX integration."""
|
||||
template_name = "moderation/dashboard.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
from .models import EditSubmission, PhotoSubmission
|
||||
from .selectors import pending_submissions_for_review
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["submissions"] = pending_submissions_for_review()
|
||||
return context
|
||||
|
||||
|
||||
class SubmissionListView(TemplateView):
|
||||
"""Submission list view with filtering."""
|
||||
template_name = "moderation/partials/dashboard_content.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
from .models import EditSubmission, PhotoSubmission
|
||||
from itertools import chain
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
status = self.request.GET.get("status", "PENDING")
|
||||
|
||||
# Get filtered submissions
|
||||
edit_submissions = EditSubmission.objects.filter(status=status).select_related("user")
|
||||
photo_submissions = PhotoSubmission.objects.filter(status=status).select_related("user")
|
||||
|
||||
# Combine and sort
|
||||
context["submissions"] = sorted(
|
||||
chain(edit_submissions, photo_submissions),
|
||||
key=lambda x: x.created_at,
|
||||
reverse=True,
|
||||
)
|
||||
return context
|
||||
|
||||
|
||||
class HistoryPageView(TemplateView):
|
||||
"""Main history page view."""
|
||||
template_name = "moderation/history.html"
|
||||
|
||||
# Create router and register viewsets
|
||||
router = DefaultRouter()
|
||||
@@ -27,11 +71,104 @@ router.register(r"users", UserModerationViewSet, basename="user-moderation")
|
||||
|
||||
app_name = "moderation"
|
||||
|
||||
urlpatterns = [
|
||||
# Include all router URLs
|
||||
path("", include(router.urls)),
|
||||
# FSM transition convenience URLs for moderation models
|
||||
fsm_transition_patterns = [
|
||||
# EditSubmission transitions
|
||||
# URL: /api/moderation/submissions/<pk>/transition/<transition_name>/
|
||||
path(
|
||||
"submissions/<int:pk>/transition/<str:transition_name>/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "editsubmission"},
|
||||
name="submission_transition",
|
||||
),
|
||||
# PhotoSubmission transitions
|
||||
# URL: /api/moderation/photos/<pk>/transition/<transition_name>/
|
||||
path(
|
||||
"photos/<int:pk>/transition/<str:transition_name>/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "photosubmission"},
|
||||
name="photo_transition",
|
||||
),
|
||||
# ModerationReport transitions
|
||||
# URL: /api/moderation/reports/<pk>/transition/<transition_name>/
|
||||
path(
|
||||
"reports/<int:pk>/transition/<str:transition_name>/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "moderationreport"},
|
||||
name="report_transition",
|
||||
),
|
||||
# ModerationQueue transitions
|
||||
# URL: /api/moderation/queue/<pk>/transition/<transition_name>/
|
||||
path(
|
||||
"queue/<int:pk>/transition/<str:transition_name>/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "moderationqueue"},
|
||||
name="queue_transition",
|
||||
),
|
||||
# BulkOperation transitions
|
||||
# URL: /api/moderation/bulk/<pk>/transition/<transition_name>/
|
||||
path(
|
||||
"bulk/<int:pk>/transition/<str:transition_name>/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "bulkoperation"},
|
||||
name="bulk_operation_transition",
|
||||
),
|
||||
# Backward compatibility aliases for EditSubmission actions
|
||||
# These redirect the old URL patterns to the FSM transition view
|
||||
path(
|
||||
"submissions/<int:pk>/approve/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "editsubmission", "transition_name": "transition_to_approved"},
|
||||
name="approve_submission",
|
||||
),
|
||||
path(
|
||||
"submissions/<int:pk>/reject/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "editsubmission", "transition_name": "transition_to_rejected"},
|
||||
name="reject_submission",
|
||||
),
|
||||
path(
|
||||
"submissions/<int:pk>/escalate/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "editsubmission", "transition_name": "transition_to_escalated"},
|
||||
name="escalate_submission",
|
||||
),
|
||||
# Backward compatibility aliases for PhotoSubmission actions
|
||||
path(
|
||||
"photos/<int:pk>/approve/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "photosubmission", "transition_name": "transition_to_approved"},
|
||||
name="approve_photo",
|
||||
),
|
||||
path(
|
||||
"photos/<int:pk>/reject/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "photosubmission", "transition_name": "transition_to_rejected"},
|
||||
name="reject_photo",
|
||||
),
|
||||
path(
|
||||
"photos/<int:pk>/escalate/",
|
||||
FSMTransitionView.as_view(),
|
||||
{"app_label": "moderation", "model_name": "photosubmission", "transition_name": "transition_to_escalated"},
|
||||
name="escalate_photo",
|
||||
),
|
||||
]
|
||||
|
||||
# HTML page patterns (for moderation dashboard)
|
||||
html_patterns = [
|
||||
path("", ModerationDashboardView.as_view(), name="dashboard"),
|
||||
path("submissions/", SubmissionListView.as_view(), name="submission_list"),
|
||||
path("history/", HistoryPageView.as_view(), name="history"),
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
# HTML page views
|
||||
*html_patterns,
|
||||
# Include all router URLs (API endpoints)
|
||||
path("api/", include(router.urls)),
|
||||
# FSM transition convenience endpoints
|
||||
] + fsm_transition_patterns
|
||||
|
||||
# URL patterns generated by the router:
|
||||
#
|
||||
# Moderation Reports:
|
||||
|
||||
Reference in New Issue
Block a user