from django.test import TestCase, Client from django.contrib.auth import get_user_model from django.contrib.auth.models import AnonymousUser from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile from django.http import JsonResponse, HttpRequest from .models import EditSubmission from .mixins import ( EditSubmissionMixin, PhotoSubmissionMixin, ModeratorRequiredMixin, AdminRequiredMixin, InlineEditMixin, HistoryMixin, ) from apps.parks.models import Company as Operator from django.views.generic import DetailView from django.test import RequestFactory import json User = get_user_model() class TestView( EditSubmissionMixin, PhotoSubmissionMixin, InlineEditMixin, HistoryMixin, DetailView, ): model = Operator template_name = "test.html" pk_url_kwarg = "pk" slug_url_kwarg = "slug" def get_context_data(self, **kwargs): if not hasattr(self, "object"): self.object = self.get_object() return super().get_context_data(**kwargs) def setup(self, request: HttpRequest, *args, **kwargs): super().setup(request, *args, **kwargs) self.request = request class ModerationMixinsTests(TestCase): def setUp(self): self.client = Client() self.factory = RequestFactory() # Create users with different roles self.user = User.objects.create_user( username="testuser", email="test@example.com", password="testpass123", ) self.moderator = User.objects.create_user( username="moderator", email="moderator@example.com", password="modpass123", role="MODERATOR", ) self.admin = User.objects.create_user( username="admin", email="admin@example.com", password="adminpass123", role="ADMIN", ) # Create test company self.operator = Operator.objects.create( name="Test Operator", website="http://example.com", description="Test Description", ) def test_edit_submission_mixin_unauthenticated(self): """Test edit submission when not logged in""" view = TestView() request = self.factory.post(f"/test/{self.operator.pk}/") request.user = AnonymousUser() view.setup(request, pk=self.operator.pk) view.kwargs = {"pk": self.operator.pk} response = view.handle_edit_submission(request, {}) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 403) def test_edit_submission_mixin_no_changes(self): """Test edit submission with no changes""" view = TestView() request = self.factory.post( f"/test/{self.operator.pk}/", data=json.dumps({}), content_type="application/json", ) request.user = self.user view.setup(request, pk=self.operator.pk) view.kwargs = {"pk": self.operator.pk} response = view.post(request) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 400) def test_edit_submission_mixin_invalid_json(self): """Test edit submission with invalid JSON""" view = TestView() request = self.factory.post( f"/test/{self.operator.pk}/", data="invalid json", content_type="application/json", ) request.user = self.user view.setup(request, pk=self.operator.pk) view.kwargs = {"pk": self.operator.pk} response = view.post(request) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 400) def test_edit_submission_mixin_regular_user(self): """Test edit submission as regular user""" view = TestView() request = self.factory.post(f"/test/{self.operator.pk}/") request.user = self.user view.setup(request, pk=self.operator.pk) view.kwargs = {"pk": self.operator.pk} changes = {"name": "New Name"} response = view.handle_edit_submission( request, changes, "Test reason", "Test source" ) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode()) self.assertFalse(data["auto_approved"]) def test_edit_submission_mixin_moderator(self): """Test edit submission as moderator""" view = TestView() request = self.factory.post(f"/test/{self.operator.pk}/") request.user = self.moderator view.setup(request, pk=self.operator.pk) view.kwargs = {"pk": self.operator.pk} changes = {"name": "New Name"} response = view.handle_edit_submission( request, changes, "Test reason", "Test source" ) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode()) self.assertTrue(data["auto_approved"]) def test_photo_submission_mixin_unauthenticated(self): """Test photo submission when not logged in""" view = TestView() view.kwargs = {"pk": self.operator.pk} view.object = self.operator request = self.factory.post( f"/test/{self.operator.pk}/", data={}, format="multipart" ) request.user = AnonymousUser() view.setup(request, pk=self.operator.pk) response = view.handle_photo_submission(request) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 403) def test_photo_submission_mixin_no_photo(self): """Test photo submission with no photo""" view = TestView() view.kwargs = {"pk": self.operator.pk} view.object = self.operator request = self.factory.post( f"/test/{self.operator.pk}/", data={}, format="multipart" ) request.user = self.user view.setup(request, pk=self.operator.pk) response = view.handle_photo_submission(request) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 400) def test_photo_submission_mixin_regular_user(self): """Test photo submission as regular user""" view = TestView() view.kwargs = {"pk": self.operator.pk} view.object = self.operator # Create a test photo file photo = SimpleUploadedFile( "test.gif", b"GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00ccc,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;", content_type="image/gif", ) request = self.factory.post( f"/test/{self.operator.pk}/", data={ "photo": photo, "caption": "Test Photo", "date_taken": "2024-01-01", }, format="multipart", ) request.user = self.user view.setup(request, pk=self.operator.pk) response = view.handle_photo_submission(request) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode()) self.assertFalse(data["auto_approved"]) def test_photo_submission_mixin_moderator(self): """Test photo submission as moderator""" view = TestView() view.kwargs = {"pk": self.operator.pk} view.object = self.operator # Create a test photo file photo = SimpleUploadedFile( "test.gif", b"GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00ccc,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;", content_type="image/gif", ) request = self.factory.post( f"/test/{self.operator.pk}/", data={ "photo": photo, "caption": "Test Photo", "date_taken": "2024-01-01", }, format="multipart", ) request.user = self.moderator view.setup(request, pk=self.operator.pk) response = view.handle_photo_submission(request) self.assertIsInstance(response, JsonResponse) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode()) self.assertTrue(data["auto_approved"]) def test_moderator_required_mixin(self): """Test moderator required mixin""" class TestModeratorView(ModeratorRequiredMixin): pass view = TestModeratorView() # Test unauthenticated user request = self.factory.get("/test/") request.user = AnonymousUser() view.request = request self.assertFalse(view.test_func()) # Test regular user request.user = self.user view.request = request self.assertFalse(view.test_func()) # Test moderator request.user = self.moderator view.request = request self.assertTrue(view.test_func()) # Test admin request.user = self.admin view.request = request self.assertTrue(view.test_func()) def test_admin_required_mixin(self): """Test admin required mixin""" class TestAdminView(AdminRequiredMixin): pass view = TestAdminView() # Test unauthenticated user request = self.factory.get("/test/") request.user = AnonymousUser() view.request = request self.assertFalse(view.test_func()) # Test regular user request.user = self.user view.request = request self.assertFalse(view.test_func()) # Test moderator request.user = self.moderator view.request = request self.assertFalse(view.test_func()) # Test admin request.user = self.admin view.request = request self.assertTrue(view.test_func()) def test_inline_edit_mixin(self): """Test inline edit mixin""" view = TestView() view.kwargs = {"pk": self.operator.pk} view.object = self.operator # Test unauthenticated user request = self.factory.get(f"/test/{self.operator.pk}/") request.user = AnonymousUser() view.setup(request, pk=self.operator.pk) context = view.get_context_data() self.assertNotIn("can_edit", context) # Test regular user request.user = self.user view.setup(request, pk=self.operator.pk) context = view.get_context_data() self.assertTrue(context["can_edit"]) self.assertFalse(context["can_auto_approve"]) # Test moderator request.user = self.moderator view.setup(request, pk=self.operator.pk) context = view.get_context_data() self.assertTrue(context["can_edit"]) self.assertTrue(context["can_auto_approve"]) def test_history_mixin(self): """Test history mixin""" view = TestView() view.kwargs = {"pk": self.operator.pk} view.object = self.operator request = self.factory.get(f"/test/{self.operator.pk}/") request.user = self.user view.setup(request, pk=self.operator.pk) # Create some edit submissions EditSubmission.objects.create( user=self.user, content_type=ContentType.objects.get_for_model(Operator), object_id=getattr(self.operator, "id", None), submission_type="EDIT", changes={"name": "New Name"}, status="APPROVED", ) context = view.get_context_data() self.assertIn("history", context) self.assertIn("edit_submissions", context) self.assertEqual(len(context["edit_submissions"]), 1)