From 1c03e4acb80a0ca7592c7dca03ca9e3d376e8b1d Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:47:19 +0000 Subject: [PATCH] Improve type hints and code organization in moderation views --- moderation/views.py | 171 +++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 89 deletions(-) diff --git a/moderation/views.py b/moderation/views.py index 2535073d..97885df2 100644 --- a/moderation/views.py +++ b/moderation/views.py @@ -1,23 +1,30 @@ from django.views.generic import ListView, TemplateView from django.shortcuts import get_object_or_404 -from django.http import HttpResponse, JsonResponse +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 -class ModeratorRequiredMixin(UserPassesTestMixin): - def test_func(self): - if not hasattr(self, 'request'): - return False - if not self.request.user.is_authenticated: - return False - return getattr(self.request.user, 'role', None) in ['MODERATOR', 'ADMIN', 'SUPERUSER'] +MODERATOR_ROLES = ['MODERATOR', 'ADMIN', 'SUPERUSER'] - def handle_no_permission(self): +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 + ) + + 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.") @@ -25,7 +32,7 @@ class ModeratorRequiredMixin(UserPassesTestMixin): class DashboardView(LoginRequiredMixin, ModeratorRequiredMixin, TemplateView): template_name = 'moderation/dashboard.html' - def get_context_data(self, **kwargs): + 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 @@ -37,16 +44,13 @@ class EditSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListVie def get_queryset(self): queryset = EditSubmission.objects.all().order_by('-created_at') - status = self.request.GET.get('status') - if status: + if status := self.request.GET.get('status'): queryset = queryset.filter(status=status) - submission_type = self.request.GET.get('type') - if submission_type: + if submission_type := self.request.GET.get('type'): queryset = queryset.filter(submission_type=submission_type) - content_type = self.request.GET.get('content_type') - if content_type: + if content_type := self.request.GET.get('content_type'): queryset = queryset.filter(content_type__model=content_type) return queryset @@ -58,122 +62,111 @@ class PhotoSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListVi def get_queryset(self): queryset = PhotoSubmission.objects.all().order_by('-created_at') - status = self.request.GET.get('status') - if status: + if status := self.request.GET.get('status'): queryset = queryset.filter(status=status) return queryset -@login_required -def submission_list(request): - """HTMX endpoint for filtered submission list""" - if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']: - return HttpResponse(status=403) - - status = request.GET.get('status') - submission_type = request.GET.get('type') - content_type = request.GET.get('content_type') - - queryset = EditSubmission.objects.all().order_by('-created_at') - - if status: - queryset = queryset.filter(status=status) - if submission_type: - queryset = queryset.filter(submission_type=submission_type) - if content_type: - queryset = queryset.filter(content_type__model=content_type) - - context = { - 'submissions': queryset - } - - html = render_to_string('moderation/partials/submission_list.html', context, request=request) +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 approve_submission(request, submission_id): +def submission_list(request: HttpRequest) -> HttpResponse: + """HTMX endpoint for filtered submission list""" + user = cast(User, request.user) + if user.role not in MODERATOR_ROLES: + 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""" - if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']: + user = cast(User, request.user) + if user.role not in MODERATOR_ROLES: return HttpResponse(status=403) submission = get_object_or_404(EditSubmission, id=submission_id) - notes = request.POST.get('notes', '') try: - submission.approve(request.user) - if notes: - submission.notes = notes - submission.save() - - context = {'submission': submission} - html = render_to_string('moderation/partials/submission_list.html', context, request=request) - return HttpResponse(html) + 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, submission_id): +def reject_submission(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for rejecting a submission""" - if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']: + user = cast(User, request.user) + if user.role not in MODERATOR_ROLES: return HttpResponse(status=403) submission = get_object_or_404(EditSubmission, id=submission_id) - notes = request.POST.get('notes', '') + submission.reject(user) + _update_submission_notes(submission, request.POST.get('notes')) - submission.reject(request.user) - if notes: - submission.notes = notes - submission.save() - - context = {'submission': submission} - html = render_to_string('moderation/partials/submission_list.html', context, request=request) - return HttpResponse(html) + return _render_submission_response('moderation/partials/submission_list.html', submission, request) @login_required -def escalate_submission(request, submission_id): +def escalate_submission(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for escalating a submission""" - if not request.user.role == 'MODERATOR': + user = cast(User, request.user) + if user.role != 'MODERATOR': return HttpResponse(status=403) submission = get_object_or_404(EditSubmission, id=submission_id) - notes = request.POST.get('notes', '') + submission.escalate(user) + _update_submission_notes(submission, request.POST.get('notes')) - submission.escalate(request.user) - if notes: - submission.notes = notes - submission.save() - - context = {'submission': submission} - html = render_to_string('moderation/partials/submission_list.html', context, request=request) - return HttpResponse(html) + return _render_submission_response('moderation/partials/submission_list.html', submission, request) @login_required -def approve_photo(request, submission_id): +def approve_photo(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for approving a photo submission""" - if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']: + user = cast(User, request.user) + if user.role not in MODERATOR_ROLES: return HttpResponse(status=403) submission = get_object_or_404(PhotoSubmission, id=submission_id) - notes = request.POST.get('notes', '') try: - submission.approve(request.user, notes) - context = {'submission': submission} - html = render_to_string('moderation/partials/photo_submission.html', context, request=request) - return HttpResponse(html) + 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, submission_id): +def reject_photo(request: HttpRequest, submission_id: int) -> HttpResponse: """HTMX endpoint for rejecting a photo submission""" - if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']: + user = cast(User, request.user) + if user.role not in MODERATOR_ROLES: return HttpResponse(status=403) submission = get_object_or_404(PhotoSubmission, id=submission_id) - notes = request.POST.get('notes', '') + submission.reject(user, request.POST.get('notes', '')) - submission.reject(request.user, notes) - context = {'submission': submission} - html = render_to_string('moderation/partials/photo_submission.html', context, request=request) - return HttpResponse(html) + return _render_submission_response('moderation/partials/photo_submission.html', submission, request)