mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 15:31:08 -05:00
Reorganize moderation dashboard structure:
- Move from /moderation/admin to /moderation to avoid conflicts - Improve template organization with partials - Add HTMX-powered navigation and filtering - Add smooth transitions and loading states - Improve photo submission handling - Add review notes functionality - Add confirmation dialogs
This commit is contained in:
@@ -1,90 +1,179 @@
|
||||
from django.views.generic import ListView
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
from django.views.generic import ListView, TemplateView
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.http import HttpResponse
|
||||
from django.contrib import messages
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
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 .models import EditSubmission
|
||||
from django.core.exceptions import PermissionDenied
|
||||
|
||||
from .models import EditSubmission, PhotoSubmission
|
||||
|
||||
class ModeratorRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
return self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']
|
||||
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']
|
||||
|
||||
class EditSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListView):
|
||||
model = EditSubmission
|
||||
template_name = 'moderation/edit_submissions.html'
|
||||
context_object_name = 'submissions'
|
||||
def handle_no_permission(self):
|
||||
if not self.request.user.is_authenticated:
|
||||
return super().handle_no_permission()
|
||||
raise PermissionDenied("You do not have moderator permissions.")
|
||||
|
||||
def get_queryset(self):
|
||||
tab = self.request.GET.get('tab', 'new')
|
||||
queryset = EditSubmission.objects.select_related('user', 'content_type')
|
||||
|
||||
# Include edits by privileged users (mods, admins, superusers) in appropriate tabs
|
||||
privileged_roles = ['MODERATOR', 'ADMIN', 'SUPERUSER']
|
||||
|
||||
if tab == 'new':
|
||||
# Show pending submissions, oldest first
|
||||
queryset = queryset.filter(status='NEW').order_by('created_at')
|
||||
elif tab == 'approved':
|
||||
# Show approved submissions and auto-approved edits by privileged users
|
||||
queryset = queryset.filter(
|
||||
Q(status='APPROVED') |
|
||||
Q(user__role__in=privileged_roles, status='NEW') # Include privileged users' edits
|
||||
).order_by('-created_at')
|
||||
elif tab == 'rejected':
|
||||
# Show rejected submissions, newest first
|
||||
queryset = queryset.filter(status='REJECTED').order_by('-created_at')
|
||||
elif tab == 'escalated' and self.request.user.role in ['ADMIN', 'SUPERUSER']:
|
||||
# Show escalated submissions, newest first
|
||||
queryset = queryset.filter(status='ESCALATED').order_by('-created_at')
|
||||
else:
|
||||
# Default to new submissions if invalid tab
|
||||
queryset = queryset.filter(status='NEW').order_by('created_at')
|
||||
|
||||
return queryset
|
||||
class DashboardView(LoginRequiredMixin, ModeratorRequiredMixin, TemplateView):
|
||||
template_name = 'moderation/dashboard.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['active_tab'] = self.request.GET.get('tab', 'new')
|
||||
context['new_count'] = EditSubmission.objects.filter(status='NEW').count()
|
||||
if self.request.user.role in ['ADMIN', 'SUPERUSER']:
|
||||
context['escalated_count'] = EditSubmission.objects.filter(status='ESCALATED').count()
|
||||
context['submissions'] = EditSubmission.objects.all().order_by('-created_at')[:10]
|
||||
return context
|
||||
|
||||
def get_template_names(self):
|
||||
if self.request.htmx:
|
||||
return ['moderation/partials/submission_list.html']
|
||||
return [self.template_name]
|
||||
class EditSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListView):
|
||||
template_name = 'moderation/edit_submission_list.html'
|
||||
context_object_name = 'submissions'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = EditSubmission.objects.all().order_by('-created_at')
|
||||
|
||||
status = self.request.GET.get('status')
|
||||
if status:
|
||||
queryset = queryset.filter(status=status)
|
||||
|
||||
submission_type = self.request.GET.get('type')
|
||||
if submission_type:
|
||||
queryset = queryset.filter(submission_type=submission_type)
|
||||
|
||||
content_type = self.request.GET.get('content_type')
|
||||
if 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')
|
||||
|
||||
status = self.request.GET.get('status')
|
||||
if 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)
|
||||
return HttpResponse(html)
|
||||
|
||||
@login_required
|
||||
def approve_submission(request, submission_id):
|
||||
"""HTMX endpoint for approving a submission"""
|
||||
if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
return HttpResponse(status=403)
|
||||
|
||||
submission = get_object_or_404(EditSubmission, id=submission_id)
|
||||
notes = request.POST.get('notes', '')
|
||||
|
||||
if request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
try:
|
||||
submission.approve(request.user)
|
||||
messages.success(request, 'Submission approved successfully')
|
||||
|
||||
# Return updated submission list for current tab
|
||||
view = EditSubmissionListView.as_view()
|
||||
return view(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)
|
||||
except ValueError as e:
|
||||
return HttpResponse(str(e), status=400)
|
||||
|
||||
@login_required
|
||||
def reject_submission(request, submission_id):
|
||||
"""HTMX endpoint for rejecting a submission"""
|
||||
if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
return HttpResponse(status=403)
|
||||
|
||||
submission = get_object_or_404(EditSubmission, id=submission_id)
|
||||
notes = request.POST.get('notes', '')
|
||||
|
||||
if request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
submission.reject(request.user)
|
||||
messages.success(request, 'Submission rejected successfully')
|
||||
submission.reject(request.user)
|
||||
if notes:
|
||||
submission.notes = notes
|
||||
submission.save()
|
||||
|
||||
# Return updated submission list for current tab
|
||||
view = EditSubmissionListView.as_view()
|
||||
return view(request)
|
||||
context = {'submission': submission}
|
||||
html = render_to_string('moderation/partials/submission_list.html', context, request=request)
|
||||
return HttpResponse(html)
|
||||
|
||||
@login_required
|
||||
def escalate_submission(request, submission_id):
|
||||
"""HTMX endpoint for escalating a submission"""
|
||||
if not request.user.role == 'MODERATOR':
|
||||
return HttpResponse(status=403)
|
||||
|
||||
submission = get_object_or_404(EditSubmission, id=submission_id)
|
||||
notes = request.POST.get('notes', '')
|
||||
|
||||
if request.user.role == 'MODERATOR':
|
||||
submission.escalate(request.user)
|
||||
messages.success(request, 'Submission escalated to admin')
|
||||
submission.escalate(request.user)
|
||||
if notes:
|
||||
submission.notes = notes
|
||||
submission.save()
|
||||
|
||||
# Return updated submission list for current tab
|
||||
view = EditSubmissionListView.as_view()
|
||||
return view(request)
|
||||
context = {'submission': submission}
|
||||
html = render_to_string('moderation/partials/submission_list.html', context, request=request)
|
||||
return HttpResponse(html)
|
||||
|
||||
@login_required
|
||||
def approve_photo(request, submission_id):
|
||||
"""HTMX endpoint for approving a photo submission"""
|
||||
if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
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)
|
||||
except Exception as e:
|
||||
return HttpResponse(str(e), status=400)
|
||||
|
||||
@login_required
|
||||
def reject_photo(request, submission_id):
|
||||
"""HTMX endpoint for rejecting a photo submission"""
|
||||
if not request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
return HttpResponse(status=403)
|
||||
|
||||
submission = get_object_or_404(PhotoSubmission, id=submission_id)
|
||||
notes = 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)
|
||||
|
||||
Reference in New Issue
Block a user