mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 18:31:09 -05:00
here we go
This commit is contained in:
@@ -16,10 +16,10 @@ class ModerationAdminSite(AdminSite):
|
||||
moderation_site = ModerationAdminSite(name='moderation')
|
||||
|
||||
class EditSubmissionAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'user_link', 'content_type', 'content_link', 'status', 'submitted_at', 'reviewed_by']
|
||||
list_filter = ['status', 'content_type', 'submitted_at']
|
||||
search_fields = ['user__username', 'reason', 'source', 'review_notes']
|
||||
readonly_fields = ['user', 'content_type', 'object_id', 'changes', 'submitted_at']
|
||||
list_display = ['id', 'user_link', 'content_type', 'content_link', 'status', 'created_at', 'handled_by']
|
||||
list_filter = ['status', 'content_type', 'created_at']
|
||||
search_fields = ['user__username', 'reason', 'source', 'notes']
|
||||
readonly_fields = ['user', 'content_type', 'object_id', 'changes', 'created_at']
|
||||
|
||||
def user_link(self, obj):
|
||||
url = reverse('admin:accounts_user_change', args=[obj.user.id])
|
||||
@@ -36,16 +36,18 @@ class EditSubmissionAdmin(admin.ModelAdmin):
|
||||
def save_model(self, request, obj, form, change):
|
||||
if 'status' in form.changed_data:
|
||||
if obj.status == 'APPROVED':
|
||||
obj.approve(request.user, obj.review_notes)
|
||||
obj.approve(request.user)
|
||||
elif obj.status == 'REJECTED':
|
||||
obj.reject(request.user, obj.review_notes)
|
||||
obj.reject(request.user)
|
||||
elif obj.status == 'ESCALATED':
|
||||
obj.escalate(request.user)
|
||||
super().save_model(request, obj, form, change)
|
||||
|
||||
class PhotoSubmissionAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'user_link', 'content_type', 'content_link', 'photo_preview', 'status', 'submitted_at', 'reviewed_by']
|
||||
list_filter = ['status', 'content_type', 'submitted_at']
|
||||
search_fields = ['user__username', 'caption', 'review_notes']
|
||||
readonly_fields = ['user', 'content_type', 'object_id', 'photo_preview', 'submitted_at']
|
||||
list_display = ['id', 'user_link', 'content_type', 'content_link', 'photo_preview', 'status', 'created_at', 'handled_by']
|
||||
list_filter = ['status', 'content_type', 'created_at']
|
||||
search_fields = ['user__username', 'caption', 'notes']
|
||||
readonly_fields = ['user', 'content_type', 'object_id', 'photo_preview', 'created_at']
|
||||
|
||||
def user_link(self, obj):
|
||||
url = reverse('admin:accounts_user_change', args=[obj.user.id])
|
||||
@@ -68,9 +70,9 @@ class PhotoSubmissionAdmin(admin.ModelAdmin):
|
||||
def save_model(self, request, obj, form, change):
|
||||
if 'status' in form.changed_data:
|
||||
if obj.status == 'APPROVED':
|
||||
obj.approve(request.user, obj.review_notes)
|
||||
obj.approve(request.user, obj.notes)
|
||||
elif obj.status == 'REJECTED':
|
||||
obj.reject(request.user, obj.review_notes)
|
||||
obj.reject(request.user, obj.notes)
|
||||
super().save_model(request, obj, form, change)
|
||||
|
||||
# Register with moderation site only
|
||||
|
||||
107
moderation/migrations/0003_rename_fields_and_update_status.py
Normal file
107
moderation/migrations/0003_rename_fields_and_update_status.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# Generated manually
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('moderation', '0002_editsubmission_submission_type_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# EditSubmission changes
|
||||
migrations.RenameField(
|
||||
model_name='editsubmission',
|
||||
old_name='submitted_at',
|
||||
new_name='created_at',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='editsubmission',
|
||||
old_name='reviewed_by',
|
||||
new_name='handled_by',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='editsubmission',
|
||||
old_name='reviewed_at',
|
||||
new_name='handled_at',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='editsubmission',
|
||||
old_name='review_notes',
|
||||
new_name='notes',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='editsubmission',
|
||||
name='status',
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
('NEW', 'New'),
|
||||
('APPROVED', 'Approved'),
|
||||
('REJECTED', 'Rejected'),
|
||||
('ESCALATED', 'Escalated'),
|
||||
],
|
||||
default='NEW',
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='editsubmission',
|
||||
name='handled_by',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='handled_submissions',
|
||||
to='accounts.user',
|
||||
),
|
||||
),
|
||||
|
||||
# PhotoSubmission changes
|
||||
migrations.RenameField(
|
||||
model_name='photosubmission',
|
||||
old_name='submitted_at',
|
||||
new_name='created_at',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='photosubmission',
|
||||
old_name='reviewed_by',
|
||||
new_name='handled_by',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='photosubmission',
|
||||
old_name='reviewed_at',
|
||||
new_name='handled_at',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='photosubmission',
|
||||
old_name='review_notes',
|
||||
new_name='notes',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photosubmission',
|
||||
name='status',
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
('NEW', 'New'),
|
||||
('APPROVED', 'Approved'),
|
||||
('REJECTED', 'Rejected'),
|
||||
('AUTO_APPROVED', 'Auto Approved'),
|
||||
],
|
||||
default='NEW',
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photosubmission',
|
||||
name='handled_by',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='handled_photos',
|
||||
to='accounts.user',
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -192,8 +192,8 @@ class InlineEditMixin:
|
||||
context['pending_edits'] = EditSubmission.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(obj),
|
||||
object_id=obj.id,
|
||||
status='PENDING'
|
||||
).select_related('user').order_by('-submitted_at')
|
||||
status='NEW'
|
||||
).select_related('user').order_by('-created_at')
|
||||
return context
|
||||
|
||||
class HistoryMixin:
|
||||
@@ -211,7 +211,7 @@ class HistoryMixin:
|
||||
content_type=content_type,
|
||||
object_id=obj.id
|
||||
).exclude(
|
||||
status='PENDING'
|
||||
).select_related('user', 'reviewed_by').order_by('-submitted_at')
|
||||
status='NEW'
|
||||
).select_related('user', 'handled_by').order_by('-created_at')
|
||||
|
||||
return context
|
||||
|
||||
@@ -7,10 +7,10 @@ from django.apps import apps
|
||||
|
||||
class EditSubmission(models.Model):
|
||||
STATUS_CHOICES = [
|
||||
('PENDING', 'Pending'),
|
||||
('NEW', 'New'),
|
||||
('APPROVED', 'Approved'),
|
||||
('REJECTED', 'Rejected'),
|
||||
('AUTO_APPROVED', 'Auto Approved'),
|
||||
('ESCALATED', 'Escalated'),
|
||||
]
|
||||
|
||||
SUBMISSION_TYPE_CHOICES = [
|
||||
@@ -53,26 +53,26 @@ class EditSubmission(models.Model):
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=STATUS_CHOICES,
|
||||
default='PENDING'
|
||||
default='NEW'
|
||||
)
|
||||
submitted_at = models.DateTimeField(auto_now_add=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
# Review details
|
||||
reviewed_by = models.ForeignKey(
|
||||
handled_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='reviewed_submissions'
|
||||
related_name='handled_submissions'
|
||||
)
|
||||
reviewed_at = models.DateTimeField(null=True, blank=True)
|
||||
review_notes = models.TextField(
|
||||
handled_at = models.DateTimeField(null=True, blank=True)
|
||||
notes = models.TextField(
|
||||
blank=True,
|
||||
help_text='Notes from the moderator about this submission'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-submitted_at']
|
||||
ordering = ['-created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['content_type', 'object_id']),
|
||||
models.Index(fields=['status']),
|
||||
@@ -96,12 +96,11 @@ class EditSubmission(models.Model):
|
||||
|
||||
return resolved_data
|
||||
|
||||
def approve(self, moderator, notes=''):
|
||||
def approve(self, user):
|
||||
"""Approve the submission and apply the changes"""
|
||||
self.status = 'APPROVED'
|
||||
self.reviewed_by = moderator
|
||||
self.reviewed_at = timezone.now()
|
||||
self.review_notes = notes
|
||||
self.handled_by = user
|
||||
self.handled_at = timezone.now()
|
||||
|
||||
model_class = self.content_type.model_class()
|
||||
resolved_data = self._resolve_foreign_keys(self.changes)
|
||||
@@ -122,42 +121,23 @@ class EditSubmission(models.Model):
|
||||
self.save()
|
||||
return obj
|
||||
|
||||
def reject(self, moderator, notes):
|
||||
def reject(self, user):
|
||||
"""Reject the submission"""
|
||||
self.status = 'REJECTED'
|
||||
self.reviewed_by = moderator
|
||||
self.reviewed_at = timezone.now()
|
||||
self.review_notes = notes
|
||||
self.handled_by = user
|
||||
self.handled_at = timezone.now()
|
||||
self.save()
|
||||
|
||||
def auto_approve(self):
|
||||
"""Auto-approve the submission (for moderators/admins)"""
|
||||
self.status = 'AUTO_APPROVED'
|
||||
self.reviewed_by = self.user
|
||||
self.reviewed_at = timezone.now()
|
||||
|
||||
model_class = self.content_type.model_class()
|
||||
resolved_data = self._resolve_foreign_keys(self.changes)
|
||||
|
||||
if self.submission_type == 'CREATE':
|
||||
# Create new object
|
||||
obj = model_class(**resolved_data)
|
||||
obj.save()
|
||||
# Update object_id after creation
|
||||
self.object_id = obj.id
|
||||
else:
|
||||
# Apply changes to existing object
|
||||
obj = self.content_object
|
||||
for field, value in resolved_data.items():
|
||||
setattr(obj, field, value)
|
||||
obj.save()
|
||||
|
||||
def escalate(self, user):
|
||||
"""Escalate the submission to admin"""
|
||||
self.status = 'ESCALATED'
|
||||
self.handled_by = user
|
||||
self.handled_at = timezone.now()
|
||||
self.save()
|
||||
return obj
|
||||
|
||||
class PhotoSubmission(models.Model):
|
||||
STATUS_CHOICES = [
|
||||
('PENDING', 'Pending'),
|
||||
('NEW', 'New'),
|
||||
('APPROVED', 'Approved'),
|
||||
('REJECTED', 'Rejected'),
|
||||
('AUTO_APPROVED', 'Auto Approved'),
|
||||
@@ -184,26 +164,26 @@ class PhotoSubmission(models.Model):
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=STATUS_CHOICES,
|
||||
default='PENDING'
|
||||
default='NEW'
|
||||
)
|
||||
submitted_at = models.DateTimeField(auto_now_add=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
# Review details
|
||||
reviewed_by = models.ForeignKey(
|
||||
handled_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='reviewed_photos'
|
||||
related_name='handled_photos'
|
||||
)
|
||||
reviewed_at = models.DateTimeField(null=True, blank=True)
|
||||
review_notes = models.TextField(
|
||||
handled_at = models.DateTimeField(null=True, blank=True)
|
||||
notes = models.TextField(
|
||||
blank=True,
|
||||
help_text='Notes from the moderator about this photo submission'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-submitted_at']
|
||||
ordering = ['-created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['content_type', 'object_id']),
|
||||
models.Index(fields=['status']),
|
||||
@@ -217,9 +197,9 @@ class PhotoSubmission(models.Model):
|
||||
from media.models import Photo
|
||||
|
||||
self.status = 'APPROVED'
|
||||
self.reviewed_by = moderator
|
||||
self.reviewed_at = timezone.now()
|
||||
self.review_notes = notes
|
||||
self.handled_by = moderator
|
||||
self.handled_at = timezone.now()
|
||||
self.notes = notes
|
||||
|
||||
# Create the approved photo
|
||||
Photo.objects.create(
|
||||
@@ -236,9 +216,9 @@ class PhotoSubmission(models.Model):
|
||||
def reject(self, moderator, notes):
|
||||
"""Reject the photo submission"""
|
||||
self.status = 'REJECTED'
|
||||
self.reviewed_by = moderator
|
||||
self.reviewed_at = timezone.now()
|
||||
self.review_notes = notes
|
||||
self.handled_by = moderator
|
||||
self.handled_at = timezone.now()
|
||||
self.notes = notes
|
||||
self.save()
|
||||
|
||||
def auto_approve(self):
|
||||
@@ -246,8 +226,8 @@ class PhotoSubmission(models.Model):
|
||||
from media.models import Photo
|
||||
|
||||
self.status = 'AUTO_APPROVED'
|
||||
self.reviewed_by = self.user
|
||||
self.reviewed_at = timezone.now()
|
||||
self.handled_by = self.user
|
||||
self.handled_at = timezone.now()
|
||||
|
||||
# Create the approved photo
|
||||
Photo.objects.create(
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
from django.urls import path, include
|
||||
from .admin import moderation_site
|
||||
from .views import EditSubmissionListView, PhotoSubmissionListView
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = 'moderation'
|
||||
|
||||
urlpatterns = [
|
||||
# Custom moderation views
|
||||
path('submissions/', include([
|
||||
path('edits/', EditSubmissionListView.as_view(), name='edit_submissions'),
|
||||
path('photos/', PhotoSubmissionListView.as_view(), name='photo_submissions'),
|
||||
])),
|
||||
|
||||
# Admin site URLs
|
||||
path('admin/', moderation_site.urls),
|
||||
path('submissions/', views.EditSubmissionListView.as_view(), name='edit_submissions'),
|
||||
path('submissions/<int:submission_id>/approve/', views.approve_submission, name='approve_submission'),
|
||||
path('submissions/<int:submission_id>/reject/', views.reject_submission, name='reject_submission'),
|
||||
path('submissions/<int:submission_id>/escalate/', views.escalate_submission, name='escalate_submission'),
|
||||
]
|
||||
|
||||
@@ -1,100 +1,90 @@
|
||||
from django.views.generic import ListView
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.http import JsonResponse
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import timezone
|
||||
from .models import EditSubmission, PhotoSubmission
|
||||
from .mixins import ModeratorRequiredMixin
|
||||
from django.http import HttpResponse
|
||||
from django.contrib import messages
|
||||
from django.db.models import Q
|
||||
from .models import EditSubmission
|
||||
|
||||
class EditSubmissionListView(ModeratorRequiredMixin, ListView):
|
||||
class ModeratorRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
return self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']
|
||||
|
||||
class EditSubmissionListView(LoginRequiredMixin, ModeratorRequiredMixin, ListView):
|
||||
model = EditSubmission
|
||||
template_name = 'moderation/admin/edit_submission_list.html'
|
||||
template_name = 'moderation/edit_submissions.html'
|
||||
context_object_name = 'submissions'
|
||||
paginate_by = 20
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset().select_related(
|
||||
'user', 'reviewed_by', 'content_type'
|
||||
).order_by('-submitted_at')
|
||||
|
||||
# Filter by status
|
||||
status = self.request.GET.get('status')
|
||||
if status:
|
||||
queryset = queryset.filter(status=status)
|
||||
|
||||
# Filter by submission type
|
||||
submission_type = self.request.GET.get('type')
|
||||
if submission_type:
|
||||
queryset = queryset.filter(submission_type=submission_type)
|
||||
|
||||
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
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
submission_id = request.POST.get('submission_id')
|
||||
action = request.POST.get('action')
|
||||
review_notes = request.POST.get('review_notes', '')
|
||||
|
||||
submission = get_object_or_404(EditSubmission, id=submission_id)
|
||||
|
||||
if action == 'approve':
|
||||
obj = submission.approve(request.user, review_notes)
|
||||
message = 'New addition approved successfully.' if submission.submission_type == 'CREATE' else 'Changes approved successfully.'
|
||||
return JsonResponse({
|
||||
'status': 'success',
|
||||
'message': message,
|
||||
'redirect_url': obj.get_absolute_url() if hasattr(obj, 'get_absolute_url') else None
|
||||
})
|
||||
elif action == 'reject':
|
||||
submission.reject(request.user, review_notes)
|
||||
message = 'New addition rejected.' if submission.submission_type == 'CREATE' else 'Changes rejected.'
|
||||
return JsonResponse({
|
||||
'status': 'success',
|
||||
'message': message
|
||||
})
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'error',
|
||||
'message': 'Invalid action.'
|
||||
}, status=400)
|
||||
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()
|
||||
return context
|
||||
|
||||
class PhotoSubmissionListView(ModeratorRequiredMixin, ListView):
|
||||
model = PhotoSubmission
|
||||
template_name = 'moderation/admin/photo_submission_list.html'
|
||||
context_object_name = 'submissions'
|
||||
paginate_by = 20
|
||||
def get_template_names(self):
|
||||
if self.request.htmx:
|
||||
return ['moderation/partials/submission_list.html']
|
||||
return [self.template_name]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset().select_related(
|
||||
'user', 'reviewed_by', 'content_type'
|
||||
).order_by('-submitted_at')
|
||||
|
||||
status = self.request.GET.get('status')
|
||||
if status:
|
||||
queryset = queryset.filter(status=status)
|
||||
|
||||
return queryset
|
||||
def approve_submission(request, submission_id):
|
||||
submission = get_object_or_404(EditSubmission, id=submission_id)
|
||||
|
||||
if request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
submission.approve(request.user)
|
||||
messages.success(request, 'Submission approved successfully')
|
||||
|
||||
# Return updated submission list for current tab
|
||||
view = EditSubmissionListView.as_view()
|
||||
return view(request)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
submission_id = request.POST.get('submission_id')
|
||||
action = request.POST.get('action')
|
||||
review_notes = request.POST.get('review_notes', '')
|
||||
|
||||
submission = get_object_or_404(PhotoSubmission, id=submission_id)
|
||||
|
||||
if action == 'approve':
|
||||
submission.approve(request.user, review_notes)
|
||||
return JsonResponse({
|
||||
'status': 'success',
|
||||
'message': 'Photo approved successfully.'
|
||||
})
|
||||
elif action == 'reject':
|
||||
submission.reject(request.user, review_notes)
|
||||
return JsonResponse({
|
||||
'status': 'success',
|
||||
'message': 'Photo rejected successfully.'
|
||||
})
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'error',
|
||||
'message': 'Invalid action.'
|
||||
}, status=400)
|
||||
def reject_submission(request, submission_id):
|
||||
submission = get_object_or_404(EditSubmission, id=submission_id)
|
||||
|
||||
if request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
|
||||
submission.reject(request.user)
|
||||
messages.success(request, 'Submission rejected successfully')
|
||||
|
||||
# Return updated submission list for current tab
|
||||
view = EditSubmissionListView.as_view()
|
||||
return view(request)
|
||||
|
||||
def escalate_submission(request, submission_id):
|
||||
submission = get_object_or_404(EditSubmission, id=submission_id)
|
||||
|
||||
if request.user.role == 'MODERATOR':
|
||||
submission.escalate(request.user)
|
||||
messages.success(request, 'Submission escalated to admin')
|
||||
|
||||
# Return updated submission list for current tab
|
||||
view = EditSubmissionListView.as_view()
|
||||
return view(request)
|
||||
|
||||
Reference in New Issue
Block a user