Improve type hints and code organization in moderation views

This commit is contained in:
pacnpal
2024-11-13 15:47:19 +00:00
parent a5ebeb51dc
commit 1c03e4acb8

View File

@@ -1,23 +1,30 @@
from django.views.generic import ListView, TemplateView from django.views.generic import ListView, TemplateView
from django.shortcuts import get_object_or_404 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.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.db.models import Q from django.db.models import Q
from django.core.exceptions import PermissionDenied 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 from .models import EditSubmission, PhotoSubmission
class ModeratorRequiredMixin(UserPassesTestMixin): MODERATOR_ROLES = ['MODERATOR', 'ADMIN', 'SUPERUSER']
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']
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: if not self.request.user.is_authenticated:
return super().handle_no_permission() return super().handle_no_permission()
raise PermissionDenied("You do not have moderator permissions.") raise PermissionDenied("You do not have moderator permissions.")
@@ -25,7 +32,7 @@ class ModeratorRequiredMixin(UserPassesTestMixin):
class DashboardView(LoginRequiredMixin, ModeratorRequiredMixin, TemplateView): class DashboardView(LoginRequiredMixin, ModeratorRequiredMixin, TemplateView):
template_name = 'moderation/dashboard.html' 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 = super().get_context_data(**kwargs)
context['submissions'] = EditSubmission.objects.all().order_by('-created_at')[:10] context['submissions'] = EditSubmission.objects.all().order_by('-created_at')[:10]
return context return context
@@ -37,16 +44,13 @@ class EditSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListVie
def get_queryset(self): def get_queryset(self):
queryset = EditSubmission.objects.all().order_by('-created_at') queryset = EditSubmission.objects.all().order_by('-created_at')
status = self.request.GET.get('status') if status := self.request.GET.get('status'):
if status:
queryset = queryset.filter(status=status) queryset = queryset.filter(status=status)
submission_type = self.request.GET.get('type') if submission_type := self.request.GET.get('type'):
if submission_type:
queryset = queryset.filter(submission_type=submission_type) queryset = queryset.filter(submission_type=submission_type)
content_type = self.request.GET.get('content_type') if content_type := self.request.GET.get('content_type'):
if content_type:
queryset = queryset.filter(content_type__model=content_type) queryset = queryset.filter(content_type__model=content_type)
return queryset return queryset
@@ -58,122 +62,111 @@ class PhotoSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListVi
def get_queryset(self): def get_queryset(self):
queryset = PhotoSubmission.objects.all().order_by('-created_at') queryset = PhotoSubmission.objects.all().order_by('-created_at')
status = self.request.GET.get('status') if status := self.request.GET.get('status'):
if status:
queryset = queryset.filter(status=status) queryset = queryset.filter(status=status)
return queryset return queryset
@login_required def _update_submission_notes(submission: EditSubmission, notes: Optional[str]) -> None:
def submission_list(request): """Update submission notes if provided."""
"""HTMX endpoint for filtered submission list""" if notes:
if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']: submission.notes = notes
return HttpResponse(status=403) submission.save()
status = request.GET.get('status') def _render_submission_response(template: str, submission: Any, request: HttpRequest) -> HttpResponse:
submission_type = request.GET.get('type') """Render submission template response."""
content_type = request.GET.get('content_type') context = {'submission': submission}
html = render_to_string(template, context, request=request)
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)
return HttpResponse(html) return HttpResponse(html)
@login_required @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""" """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) return HttpResponse(status=403)
submission = get_object_or_404(EditSubmission, id=submission_id) submission = get_object_or_404(EditSubmission, id=submission_id)
notes = request.POST.get('notes', '')
try: try:
submission.approve(request.user) submission.approve(user)
if notes: _update_submission_notes(submission, request.POST.get('notes'))
submission.notes = notes return _render_submission_response('moderation/partials/submission_list.html', submission, request)
submission.save()
context = {'submission': submission}
html = render_to_string('moderation/partials/submission_list.html', context, request=request)
return HttpResponse(html)
except ValueError as e: except ValueError as e:
return HttpResponse(str(e), status=400) return HttpResponse(str(e), status=400)
@login_required @login_required
def reject_submission(request, submission_id): def reject_submission(request: HttpRequest, submission_id: int) -> HttpResponse:
"""HTMX endpoint for rejecting a submission""" """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) return HttpResponse(status=403)
submission = get_object_or_404(EditSubmission, id=submission_id) 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) return _render_submission_response('moderation/partials/submission_list.html', submission, request)
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)
@login_required @login_required
def escalate_submission(request, submission_id): def escalate_submission(request: HttpRequest, submission_id: int) -> HttpResponse:
"""HTMX endpoint for escalating a submission""" """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) return HttpResponse(status=403)
submission = get_object_or_404(EditSubmission, id=submission_id) 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) return _render_submission_response('moderation/partials/submission_list.html', submission, request)
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)
@login_required @login_required
def approve_photo(request, submission_id): def approve_photo(request: HttpRequest, submission_id: int) -> HttpResponse:
"""HTMX endpoint for approving a photo submission""" """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) return HttpResponse(status=403)
submission = get_object_or_404(PhotoSubmission, id=submission_id) submission = get_object_or_404(PhotoSubmission, id=submission_id)
notes = request.POST.get('notes', '')
try: try:
submission.approve(request.user, notes) submission.approve(user, request.POST.get('notes', ''))
context = {'submission': submission} return _render_submission_response('moderation/partials/photo_submission.html', submission, request)
html = render_to_string('moderation/partials/photo_submission.html', context, request=request)
return HttpResponse(html)
except Exception as e: except Exception as e:
return HttpResponse(str(e), status=400) return HttpResponse(str(e), status=400)
@login_required @login_required
def reject_photo(request, submission_id): def reject_photo(request: HttpRequest, submission_id: int) -> HttpResponse:
"""HTMX endpoint for rejecting a photo submission""" """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) return HttpResponse(status=403)
submission = get_object_or_404(PhotoSubmission, id=submission_id) 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) return _render_submission_response('moderation/partials/photo_submission.html', submission, request)
context = {'submission': submission}
html = render_to_string('moderation/partials/photo_submission.html', context, request=request)
return HttpResponse(html)