mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 13:51:09 -05:00
218 lines
7.7 KiB
Python
218 lines
7.7 KiB
Python
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.http import JsonResponse, HttpResponseForbidden
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.utils import timezone
|
|
import json
|
|
from .models import EditSubmission, PhotoSubmission
|
|
|
|
class EditSubmissionMixin:
|
|
"""
|
|
Mixin for handling edit submissions with proper moderation.
|
|
"""
|
|
def handle_edit_submission(self, request, changes, reason='', source='', submission_type='EDIT'):
|
|
"""
|
|
Handle an edit submission based on user's role.
|
|
|
|
Args:
|
|
request: The HTTP request
|
|
changes: Dict of field changes {field_name: new_value}
|
|
reason: Why this edit is needed
|
|
source: Source of information (optional)
|
|
submission_type: 'EDIT' or 'CREATE'
|
|
|
|
Returns:
|
|
JsonResponse with status and message
|
|
"""
|
|
if not request.user.is_authenticated:
|
|
return JsonResponse({
|
|
'status': 'error',
|
|
'message': 'You must be logged in to make edits.'
|
|
}, status=403)
|
|
|
|
content_type = ContentType.objects.get_for_model(self.model)
|
|
|
|
# Create the submission
|
|
submission = EditSubmission(
|
|
user=request.user,
|
|
content_type=content_type,
|
|
submission_type=submission_type,
|
|
changes=changes,
|
|
reason=reason,
|
|
source=source
|
|
)
|
|
|
|
# For edits, set the object_id
|
|
if submission_type == 'EDIT':
|
|
obj = self.get_object()
|
|
submission.object_id = obj.id
|
|
|
|
# Auto-approve for moderators and above
|
|
if request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
|
obj = submission.auto_approve()
|
|
return JsonResponse({
|
|
'status': 'success',
|
|
'message': 'Changes saved successfully.',
|
|
'auto_approved': True,
|
|
'redirect_url': obj.get_absolute_url() if hasattr(obj, 'get_absolute_url') else None
|
|
})
|
|
|
|
# Submit for approval for regular users
|
|
submission.save()
|
|
return JsonResponse({
|
|
'status': 'success',
|
|
'message': 'Your changes have been submitted for approval.',
|
|
'auto_approved': False
|
|
})
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
"""Handle POST requests for editing"""
|
|
if not request.user.is_authenticated:
|
|
return JsonResponse({
|
|
'status': 'error',
|
|
'message': 'You must be logged in to make edits.'
|
|
}, status=403)
|
|
|
|
try:
|
|
data = json.loads(request.body)
|
|
changes = data.get('changes', {})
|
|
reason = data.get('reason', '')
|
|
source = data.get('source', '')
|
|
submission_type = data.get('submission_type', 'EDIT')
|
|
|
|
if not changes:
|
|
return JsonResponse({
|
|
'status': 'error',
|
|
'message': 'No changes provided.'
|
|
}, status=400)
|
|
|
|
if not reason and request.user.role == 'USER':
|
|
return JsonResponse({
|
|
'status': 'error',
|
|
'message': 'Please provide a reason for your changes.'
|
|
}, status=400)
|
|
|
|
return self.handle_edit_submission(
|
|
request, changes, reason, source, submission_type
|
|
)
|
|
|
|
except json.JSONDecodeError:
|
|
return JsonResponse({
|
|
'status': 'error',
|
|
'message': 'Invalid JSON data.'
|
|
}, status=400)
|
|
except Exception as e:
|
|
return JsonResponse({
|
|
'status': 'error',
|
|
'message': str(e)
|
|
}, status=500)
|
|
|
|
class PhotoSubmissionMixin:
|
|
"""
|
|
Mixin for handling photo submissions with proper moderation.
|
|
"""
|
|
def handle_photo_submission(self, request):
|
|
"""Handle a photo submission based on user's role"""
|
|
if not request.user.is_authenticated:
|
|
return JsonResponse({
|
|
'status': 'error',
|
|
'message': 'You must be logged in to upload photos.'
|
|
}, status=403)
|
|
|
|
if not request.FILES.get('photo'):
|
|
return JsonResponse({
|
|
'status': 'error',
|
|
'message': 'No photo provided.'
|
|
}, status=400)
|
|
|
|
obj = self.get_object()
|
|
content_type = ContentType.objects.get_for_model(obj)
|
|
|
|
submission = PhotoSubmission(
|
|
user=request.user,
|
|
content_type=content_type,
|
|
object_id=obj.id,
|
|
photo=request.FILES['photo'],
|
|
caption=request.POST.get('caption', ''),
|
|
date_taken=request.POST.get('date_taken')
|
|
)
|
|
|
|
# Auto-approve for moderators and above
|
|
if request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
|
submission.auto_approve()
|
|
return JsonResponse({
|
|
'status': 'success',
|
|
'message': 'Photo uploaded successfully.',
|
|
'auto_approved': True
|
|
})
|
|
|
|
# Submit for approval for regular users
|
|
submission.save()
|
|
return JsonResponse({
|
|
'status': 'success',
|
|
'message': 'Your photo has been submitted for approval.',
|
|
'auto_approved': False
|
|
})
|
|
|
|
class ModeratorRequiredMixin(UserPassesTestMixin):
|
|
"""Require moderator or higher role for access"""
|
|
def test_func(self):
|
|
return (
|
|
self.request.user.is_authenticated and
|
|
self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']
|
|
)
|
|
|
|
def handle_no_permission(self):
|
|
if not self.request.user.is_authenticated:
|
|
return super().handle_no_permission()
|
|
return HttpResponseForbidden("You must be a moderator to access this page.")
|
|
|
|
class AdminRequiredMixin(UserPassesTestMixin):
|
|
"""Require admin or superuser role for access"""
|
|
def test_func(self):
|
|
return (
|
|
self.request.user.is_authenticated and
|
|
self.request.user.role in ['ADMIN', 'SUPERUSER']
|
|
)
|
|
|
|
def handle_no_permission(self):
|
|
if not self.request.user.is_authenticated:
|
|
return super().handle_no_permission()
|
|
return HttpResponseForbidden("You must be an admin to access this page.")
|
|
|
|
class InlineEditMixin:
|
|
"""Add inline editing context to views"""
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
if self.request.user.is_authenticated:
|
|
context['can_edit'] = True
|
|
context['can_auto_approve'] = self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']
|
|
if hasattr(self, 'get_object'):
|
|
obj = self.get_object()
|
|
context['pending_edits'] = EditSubmission.objects.filter(
|
|
content_type=ContentType.objects.get_for_model(obj),
|
|
object_id=obj.id,
|
|
status='NEW'
|
|
).select_related('user').order_by('-created_at')
|
|
return context
|
|
|
|
class HistoryMixin:
|
|
"""Add edit history context to views"""
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
obj = self.get_object()
|
|
|
|
# Get historical records
|
|
context['history'] = obj.history.all().select_related('history_user')
|
|
|
|
# Get related edit submissions
|
|
content_type = ContentType.objects.get_for_model(obj)
|
|
context['edit_submissions'] = EditSubmission.objects.filter(
|
|
content_type=content_type,
|
|
object_id=obj.id
|
|
).exclude(
|
|
status='NEW'
|
|
).select_related('user', 'handled_by').order_by('-created_at')
|
|
|
|
return context
|