mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-30 08:07:01 -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:
@@ -6,7 +6,6 @@ state log, and history event admin classes including query optimization
|
||||
and custom moderation actions.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import RequestFactory, TestCase
|
||||
@@ -14,7 +13,6 @@ from django.test import RequestFactory, TestCase
|
||||
from apps.moderation.admin import (
|
||||
EditSubmissionAdmin,
|
||||
HistoryEventAdmin,
|
||||
ModerationAdminSite,
|
||||
PhotoSubmissionAdmin,
|
||||
StateLogAdmin,
|
||||
moderation_site,
|
||||
|
||||
@@ -9,18 +9,18 @@ This module tests end-to-end moderation workflows including:
|
||||
- Bulk operation workflow
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
from unittest.mock import patch, Mock
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class SubmissionApprovalWorkflowTests(TestCase):
|
||||
"""Tests for the complete submission approval workflow."""
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
"""Set up test data for all tests."""
|
||||
@@ -42,22 +42,22 @@ class SubmissionApprovalWorkflowTests(TestCase):
|
||||
password='testpass123',
|
||||
role='ADMIN'
|
||||
)
|
||||
|
||||
|
||||
def test_edit_submission_approval_workflow(self):
|
||||
"""
|
||||
Test complete edit submission approval workflow.
|
||||
|
||||
|
||||
Flow: User submits → Moderator reviews → Moderator approves → Changes applied
|
||||
"""
|
||||
from apps.moderation.models import EditSubmission
|
||||
from apps.parks.models import Company
|
||||
|
||||
|
||||
# Create target object
|
||||
company = Company.objects.create(
|
||||
name='Test Company',
|
||||
description='Original description'
|
||||
)
|
||||
|
||||
|
||||
# User submits an edit
|
||||
content_type = ContentType.objects.get_for_model(company)
|
||||
submission = EditSubmission.objects.create(
|
||||
@@ -69,31 +69,31 @@ class SubmissionApprovalWorkflowTests(TestCase):
|
||||
status='PENDING',
|
||||
reason='Fixing typo'
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(submission.status, 'PENDING')
|
||||
self.assertIsNone(submission.handled_by)
|
||||
self.assertIsNone(submission.handled_at)
|
||||
|
||||
|
||||
# Moderator approves
|
||||
submission.transition_to_approved(user=self.moderator)
|
||||
submission.handled_by = self.moderator
|
||||
submission.handled_at = timezone.now()
|
||||
submission.save()
|
||||
|
||||
|
||||
submission.refresh_from_db()
|
||||
self.assertEqual(submission.status, 'APPROVED')
|
||||
self.assertEqual(submission.handled_by, self.moderator)
|
||||
self.assertIsNotNone(submission.handled_at)
|
||||
|
||||
|
||||
def test_photo_submission_approval_workflow(self):
|
||||
"""
|
||||
Test complete photo submission approval workflow.
|
||||
|
||||
|
||||
Flow: User submits photo → Moderator reviews → Moderator approves → Photo created
|
||||
"""
|
||||
from apps.moderation.models import PhotoSubmission
|
||||
from apps.parks.models import Park, Company
|
||||
|
||||
from apps.parks.models import Company, Park
|
||||
|
||||
# Create target park
|
||||
operator = Company.objects.create(
|
||||
name='Test Operator',
|
||||
@@ -106,7 +106,7 @@ class SubmissionApprovalWorkflowTests(TestCase):
|
||||
status='OPERATING',
|
||||
timezone='America/New_York'
|
||||
)
|
||||
|
||||
|
||||
# User submits a photo
|
||||
content_type = ContentType.objects.get_for_model(park)
|
||||
submission = PhotoSubmission.objects.create(
|
||||
@@ -117,22 +117,22 @@ class SubmissionApprovalWorkflowTests(TestCase):
|
||||
photo_type='GENERAL',
|
||||
description='Beautiful park entrance'
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(submission.status, 'PENDING')
|
||||
|
||||
|
||||
# Moderator approves
|
||||
submission.transition_to_approved(user=self.moderator)
|
||||
submission.handled_by = self.moderator
|
||||
submission.handled_at = timezone.now()
|
||||
submission.save()
|
||||
|
||||
|
||||
submission.refresh_from_db()
|
||||
self.assertEqual(submission.status, 'APPROVED')
|
||||
|
||||
|
||||
class SubmissionRejectionWorkflowTests(TestCase):
|
||||
"""Tests for the submission rejection workflow."""
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.regular_user = User.objects.create_user(
|
||||
@@ -147,21 +147,21 @@ class SubmissionRejectionWorkflowTests(TestCase):
|
||||
password='testpass123',
|
||||
role='MODERATOR'
|
||||
)
|
||||
|
||||
|
||||
def test_edit_submission_rejection_with_reason(self):
|
||||
"""
|
||||
Test rejection workflow with reason.
|
||||
|
||||
|
||||
Flow: User submits → Moderator rejects with reason → User notified
|
||||
"""
|
||||
from apps.moderation.models import EditSubmission
|
||||
from apps.parks.models import Company
|
||||
|
||||
|
||||
company = Company.objects.create(
|
||||
name='Test Company',
|
||||
description='Original'
|
||||
)
|
||||
|
||||
|
||||
content_type = ContentType.objects.get_for_model(company)
|
||||
submission = EditSubmission.objects.create(
|
||||
user=self.regular_user,
|
||||
@@ -172,14 +172,14 @@ class SubmissionRejectionWorkflowTests(TestCase):
|
||||
status='PENDING',
|
||||
reason='Name change request'
|
||||
)
|
||||
|
||||
|
||||
# Moderator rejects
|
||||
submission.transition_to_rejected(user=self.moderator)
|
||||
submission.handled_by = self.moderator
|
||||
submission.handled_at = timezone.now()
|
||||
submission.notes = 'Rejected: Content appears to be spam'
|
||||
submission.save()
|
||||
|
||||
|
||||
submission.refresh_from_db()
|
||||
self.assertEqual(submission.status, 'REJECTED')
|
||||
self.assertIn('spam', submission.notes.lower())
|
||||
@@ -187,7 +187,7 @@ class SubmissionRejectionWorkflowTests(TestCase):
|
||||
|
||||
class SubmissionEscalationWorkflowTests(TestCase):
|
||||
"""Tests for the submission escalation workflow."""
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.regular_user = User.objects.create_user(
|
||||
@@ -208,21 +208,21 @@ class SubmissionEscalationWorkflowTests(TestCase):
|
||||
password='testpass123',
|
||||
role='ADMIN'
|
||||
)
|
||||
|
||||
|
||||
def test_escalation_workflow(self):
|
||||
"""
|
||||
Test complete escalation workflow.
|
||||
|
||||
|
||||
Flow: User submits → Moderator escalates → Admin reviews → Admin approves
|
||||
"""
|
||||
from apps.moderation.models import EditSubmission
|
||||
from apps.parks.models import Company
|
||||
|
||||
|
||||
company = Company.objects.create(
|
||||
name='Sensitive Company',
|
||||
description='Original'
|
||||
)
|
||||
|
||||
|
||||
content_type = ContentType.objects.get_for_model(company)
|
||||
submission = EditSubmission.objects.create(
|
||||
user=self.regular_user,
|
||||
@@ -233,20 +233,20 @@ class SubmissionEscalationWorkflowTests(TestCase):
|
||||
status='PENDING',
|
||||
reason='Major name change'
|
||||
)
|
||||
|
||||
|
||||
# Moderator escalates
|
||||
submission.transition_to_escalated(user=self.moderator)
|
||||
submission.notes = 'Escalated: Major change needs admin review'
|
||||
submission.save()
|
||||
|
||||
|
||||
self.assertEqual(submission.status, 'ESCALATED')
|
||||
|
||||
|
||||
# Admin approves
|
||||
submission.transition_to_approved(user=self.admin)
|
||||
submission.handled_by = self.admin
|
||||
submission.handled_at = timezone.now()
|
||||
submission.save()
|
||||
|
||||
|
||||
submission.refresh_from_db()
|
||||
self.assertEqual(submission.status, 'APPROVED')
|
||||
self.assertEqual(submission.handled_by, self.admin)
|
||||
@@ -254,7 +254,7 @@ class SubmissionEscalationWorkflowTests(TestCase):
|
||||
|
||||
class ReportHandlingWorkflowTests(TestCase):
|
||||
"""Tests for the moderation report handling workflow."""
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.reporter = User.objects.create_user(
|
||||
@@ -269,23 +269,23 @@ class ReportHandlingWorkflowTests(TestCase):
|
||||
password='testpass123',
|
||||
role='MODERATOR'
|
||||
)
|
||||
|
||||
|
||||
def test_report_resolution_workflow(self):
|
||||
"""
|
||||
Test complete report resolution workflow.
|
||||
|
||||
|
||||
Flow: User reports → Moderator assigned → Moderator investigates → Resolved
|
||||
"""
|
||||
from apps.moderation.models import ModerationReport
|
||||
from apps.parks.models import Company
|
||||
|
||||
|
||||
reported_company = Company.objects.create(
|
||||
name='Problematic Company',
|
||||
description='Some inappropriate content'
|
||||
)
|
||||
|
||||
|
||||
content_type = ContentType.objects.get_for_model(reported_company)
|
||||
|
||||
|
||||
# User reports content
|
||||
report = ModerationReport.objects.create(
|
||||
report_type='CONTENT',
|
||||
@@ -298,44 +298,44 @@ class ReportHandlingWorkflowTests(TestCase):
|
||||
description='This content is inappropriate',
|
||||
reported_by=self.reporter
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(report.status, 'PENDING')
|
||||
|
||||
|
||||
# Moderator claims and starts review
|
||||
report.transition_to_under_review(user=self.moderator)
|
||||
report.assigned_moderator = self.moderator
|
||||
report.save()
|
||||
|
||||
|
||||
self.assertEqual(report.status, 'UNDER_REVIEW')
|
||||
self.assertEqual(report.assigned_moderator, self.moderator)
|
||||
|
||||
|
||||
# Moderator resolves
|
||||
report.transition_to_resolved(user=self.moderator)
|
||||
report.resolution_action = 'CONTENT_REMOVED'
|
||||
report.resolution_notes = 'Content was removed'
|
||||
report.resolved_at = timezone.now()
|
||||
report.save()
|
||||
|
||||
|
||||
report.refresh_from_db()
|
||||
self.assertEqual(report.status, 'RESOLVED')
|
||||
self.assertIsNotNone(report.resolved_at)
|
||||
|
||||
|
||||
def test_report_dismissal_workflow(self):
|
||||
"""
|
||||
Test report dismissal workflow for invalid reports.
|
||||
|
||||
|
||||
Flow: User reports → Moderator reviews → Moderator dismisses
|
||||
"""
|
||||
from apps.moderation.models import ModerationReport
|
||||
from apps.parks.models import Company
|
||||
|
||||
|
||||
company = Company.objects.create(
|
||||
name='Valid Company',
|
||||
description='Normal content'
|
||||
)
|
||||
|
||||
|
||||
content_type = ContentType.objects.get_for_model(company)
|
||||
|
||||
|
||||
report = ModerationReport.objects.create(
|
||||
report_type='CONTENT',
|
||||
status='PENDING',
|
||||
@@ -347,25 +347,25 @@ class ReportHandlingWorkflowTests(TestCase):
|
||||
description='I just do not like this',
|
||||
reported_by=self.reporter
|
||||
)
|
||||
|
||||
|
||||
# Moderator claims
|
||||
report.transition_to_under_review(user=self.moderator)
|
||||
report.assigned_moderator = self.moderator
|
||||
report.save()
|
||||
|
||||
|
||||
# Moderator dismisses as invalid
|
||||
report.transition_to_dismissed(user=self.moderator)
|
||||
report.resolution_notes = 'Report does not violate any guidelines'
|
||||
report.resolved_at = timezone.now()
|
||||
report.save()
|
||||
|
||||
|
||||
report.refresh_from_db()
|
||||
self.assertEqual(report.status, 'DISMISSED')
|
||||
|
||||
|
||||
class BulkOperationWorkflowTests(TestCase):
|
||||
"""Tests for bulk operation workflows."""
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.admin = User.objects.create_user(
|
||||
@@ -374,15 +374,15 @@ class BulkOperationWorkflowTests(TestCase):
|
||||
password='testpass123',
|
||||
role='ADMIN'
|
||||
)
|
||||
|
||||
|
||||
def test_bulk_operation_success_workflow(self):
|
||||
"""
|
||||
Test successful bulk operation workflow.
|
||||
|
||||
|
||||
Flow: Admin creates → Operation runs → Progress tracked → Completed
|
||||
"""
|
||||
from apps.moderation.models import BulkOperation
|
||||
|
||||
|
||||
operation = BulkOperation.objects.create(
|
||||
operation_type='APPROVE_SUBMISSIONS',
|
||||
status='PENDING',
|
||||
@@ -391,39 +391,39 @@ class BulkOperationWorkflowTests(TestCase):
|
||||
created_by=self.admin,
|
||||
parameters={'submission_ids': list(range(1, 11))}
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(operation.status, 'PENDING')
|
||||
|
||||
|
||||
# Start operation
|
||||
operation.transition_to_running(user=self.admin)
|
||||
operation.started_at = timezone.now()
|
||||
operation.save()
|
||||
|
||||
|
||||
self.assertEqual(operation.status, 'RUNNING')
|
||||
|
||||
|
||||
# Simulate progress
|
||||
for i in range(1, 11):
|
||||
operation.processed_items = i
|
||||
operation.save()
|
||||
|
||||
|
||||
# Complete operation
|
||||
operation.transition_to_completed(user=self.admin)
|
||||
operation.completed_at = timezone.now()
|
||||
operation.results = {'approved': 10, 'failed': 0}
|
||||
operation.save()
|
||||
|
||||
|
||||
operation.refresh_from_db()
|
||||
self.assertEqual(operation.status, 'COMPLETED')
|
||||
self.assertEqual(operation.processed_items, 10)
|
||||
|
||||
|
||||
def test_bulk_operation_failure_workflow(self):
|
||||
"""
|
||||
Test bulk operation failure workflow.
|
||||
|
||||
|
||||
Flow: Admin creates → Operation runs → Error occurs → Failed
|
||||
"""
|
||||
from apps.moderation.models import BulkOperation
|
||||
|
||||
|
||||
operation = BulkOperation.objects.create(
|
||||
operation_type='DELETE_CONTENT',
|
||||
status='PENDING',
|
||||
@@ -432,11 +432,11 @@ class BulkOperationWorkflowTests(TestCase):
|
||||
created_by=self.admin,
|
||||
parameters={'content_ids': list(range(1, 6))}
|
||||
)
|
||||
|
||||
|
||||
operation.transition_to_running(user=self.admin)
|
||||
operation.started_at = timezone.now()
|
||||
operation.save()
|
||||
|
||||
|
||||
# Simulate partial progress then failure
|
||||
operation.processed_items = 2
|
||||
operation.failed_items = 3
|
||||
@@ -444,19 +444,19 @@ class BulkOperationWorkflowTests(TestCase):
|
||||
operation.completed_at = timezone.now()
|
||||
operation.results = {'error': 'Database connection lost', 'processed': 2}
|
||||
operation.save()
|
||||
|
||||
|
||||
operation.refresh_from_db()
|
||||
self.assertEqual(operation.status, 'FAILED')
|
||||
self.assertEqual(operation.failed_items, 3)
|
||||
|
||||
|
||||
def test_bulk_operation_cancellation_workflow(self):
|
||||
"""
|
||||
Test bulk operation cancellation workflow.
|
||||
|
||||
|
||||
Flow: Admin creates → Operation runs → Admin cancels
|
||||
"""
|
||||
from apps.moderation.models import BulkOperation
|
||||
|
||||
|
||||
operation = BulkOperation.objects.create(
|
||||
operation_type='BATCH_UPDATE',
|
||||
status='PENDING',
|
||||
@@ -466,20 +466,20 @@ class BulkOperationWorkflowTests(TestCase):
|
||||
parameters={'update_field': 'status'},
|
||||
can_cancel=True
|
||||
)
|
||||
|
||||
|
||||
operation.transition_to_running(user=self.admin)
|
||||
operation.save()
|
||||
|
||||
|
||||
# Partial progress
|
||||
operation.processed_items = 30
|
||||
operation.save()
|
||||
|
||||
|
||||
# Admin cancels
|
||||
operation.transition_to_cancelled(user=self.admin)
|
||||
operation.completed_at = timezone.now()
|
||||
operation.results = {'cancelled_at': 30, 'reason': 'User requested cancellation'}
|
||||
operation.save()
|
||||
|
||||
|
||||
operation.refresh_from_db()
|
||||
self.assertEqual(operation.status, 'CANCELLED')
|
||||
self.assertEqual(operation.processed_items, 30)
|
||||
@@ -487,7 +487,7 @@ class BulkOperationWorkflowTests(TestCase):
|
||||
|
||||
class ModerationQueueWorkflowTests(TestCase):
|
||||
"""Tests for moderation queue workflows."""
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.moderator = User.objects.create_user(
|
||||
@@ -496,15 +496,15 @@ class ModerationQueueWorkflowTests(TestCase):
|
||||
password='testpass123',
|
||||
role='MODERATOR'
|
||||
)
|
||||
|
||||
|
||||
def test_queue_completion_workflow(self):
|
||||
"""
|
||||
Test queue item completion workflow.
|
||||
|
||||
|
||||
Flow: Item created → Moderator claims → Work done → Completed
|
||||
"""
|
||||
from apps.moderation.models import ModerationQueue
|
||||
|
||||
|
||||
queue_item = ModerationQueue.objects.create(
|
||||
queue_type='SUBMISSION_REVIEW',
|
||||
status='PENDING',
|
||||
@@ -512,21 +512,21 @@ class ModerationQueueWorkflowTests(TestCase):
|
||||
item_type='edit_submission',
|
||||
item_id=123
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(queue_item.status, 'PENDING')
|
||||
|
||||
|
||||
# Moderator claims
|
||||
queue_item.transition_to_in_progress(user=self.moderator)
|
||||
queue_item.assigned_to = self.moderator
|
||||
queue_item.assigned_at = timezone.now()
|
||||
queue_item.save()
|
||||
|
||||
|
||||
self.assertEqual(queue_item.status, 'IN_PROGRESS')
|
||||
|
||||
|
||||
# Work completed
|
||||
queue_item.transition_to_completed(user=self.moderator)
|
||||
queue_item.completed_at = timezone.now()
|
||||
queue_item.save()
|
||||
|
||||
|
||||
queue_item.refresh_from_db()
|
||||
self.assertEqual(queue_item.status, 'COMPLETED')
|
||||
|
||||
Reference in New Issue
Block a user