from django.views.generic import ListView, TemplateView from django.shortcuts import get_object_or_404 from django.http import HttpResponse, JsonResponse, HttpRequest from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.contrib.auth.decorators import login_required from django.template.loader import render_to_string from django.db.models import Q from django.core.exceptions import PermissionDenied from typing import Optional, Any, cast from accounts.models import User # Import custom User model from .models import EditSubmission, PhotoSubmission MODERATOR_ROLES = ['MODERATOR', 'ADMIN', 'SUPERUSER'] class ModeratorRequiredMixin(UserPassesTestMixin): request: HttpRequest def test_func(self) -> bool: """Check if user has moderator permissions.""" user = cast(User, self.request.user) return ( user.is_authenticated and (getattr(user, 'role', None) in MODERATOR_ROLES or user.is_superuser) ) def handle_no_permission(self) -> HttpResponse: if not self.request.user.is_authenticated: return super().handle_no_permission() raise PermissionDenied("You do not have moderator permissions.") class DashboardView(LoginRequiredMixin, ModeratorRequiredMixin, TemplateView): template_name = 'moderation/dashboard.html' def get_context_data(self, **kwargs: Any) -> dict[str, Any]: context = super().get_context_data(**kwargs) context['submissions'] = EditSubmission.objects.all().order_by('-created_at')[:10] return context class EditSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListView): context_object_name = 'submissions' def get_template_names(self): if self.request.headers.get('HX-Request'): return ['moderation/partials/edit_submission_content.html'] return ['moderation/edit_submission_list.html'] def get_queryset(self): queryset = EditSubmission.objects.all().order_by('-created_at') if status := self.request.GET.get('status'): queryset = queryset.filter(status=status) if submission_type := self.request.GET.get('type'): queryset = queryset.filter(submission_type=submission_type) if content_type := self.request.GET.get('content_type'): queryset = queryset.filter(content_type__model=content_type) return queryset class PhotoSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListView): template_name = 'moderation/photo_submission_list.html' context_object_name = 'submissions' def get_queryset(self): queryset = PhotoSubmission.objects.all().order_by('-created_at') if status := self.request.GET.get('status'): queryset = queryset.filter(status=status) return queryset def _update_submission_notes(submission: EditSubmission, notes: Optional[str]) -> None: """Update submission notes if provided.""" if notes: submission.notes = notes submission.save() def _render_submission_response(template: str, submission: Any, request: HttpRequest) -> HttpResponse: """Render submission template response.""" context = {'submission': submission} html = render_to_string(template, context, request=request) return HttpResponse(html) @login_required def submission_list(request: HttpRequest) -> HttpResponse: """HTMX endpoint for filtered submission list""" user = cast(User, request.user) if not (user.role in MODERATOR_ROLES or user.is_superuser): return HttpResponse(status=403) queryset = EditSubmission.objects.all().order_by('-created_at') if status := request.GET.get('status'): queryset = queryset.filter(status=status) if submission_type := request.GET.get('type'): queryset = queryset.filter(submission_type=submission_type) if content_type := request.GET.get('content_type'): queryset = queryset.filter(content_type__model=content_type) html = render_to_string( 'moderation/partials/submission_list.html', {'submissions': queryset}, request=request ) return HttpResponse(html) @login_required def approve_submission(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for approving a submission""" user = cast(User, request.user) if not (user.role in MODERATOR_ROLES or user.is_superuser): return HttpResponse(status=403) submission = get_object_or_404(EditSubmission, id=submission_id) try: submission.approve(user) _update_submission_notes(submission, request.POST.get('notes')) return _render_submission_response('moderation/partials/submission_list.html', submission, request) except ValueError as e: return HttpResponse(str(e), status=400) @login_required def reject_submission(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for rejecting a submission""" user = cast(User, request.user) if not (user.role in MODERATOR_ROLES or user.is_superuser): return HttpResponse(status=403) submission = get_object_or_404(EditSubmission, id=submission_id) submission.reject(user) _update_submission_notes(submission, request.POST.get('notes')) return _render_submission_response('moderation/partials/submission_list.html', submission, request) @login_required def escalate_submission(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for escalating a submission""" user = cast(User, request.user) if user.role != 'MODERATOR' and not user.is_superuser: return HttpResponse(status=403) submission = get_object_or_404(EditSubmission, id=submission_id) submission.escalate(user) _update_submission_notes(submission, request.POST.get('notes')) return _render_submission_response('moderation/partials/submission_list.html', submission, request) @login_required def approve_photo(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for approving a photo submission""" user = cast(User, request.user) if not (user.role in MODERATOR_ROLES or user.is_superuser): return HttpResponse(status=403) submission = get_object_or_404(PhotoSubmission, id=submission_id) try: submission.approve(user, request.POST.get('notes', '')) return _render_submission_response('moderation/partials/photo_submission.html', submission, request) except Exception as e: return HttpResponse(str(e), status=400) @login_required def reject_photo(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for rejecting a photo submission""" user = cast(User, request.user) if not (user.role in MODERATOR_ROLES or user.is_superuser): return HttpResponse(status=403) submission = get_object_or_404(PhotoSubmission, id=submission_id) submission.reject(user, request.POST.get('notes', '')) return _render_submission_response('moderation/partials/photo_submission.html', submission, request)