Phase 5: Events Admin — 4 new event endpoints (stats, list, detail, moderate)
This commit is contained in:
@@ -22,4 +22,9 @@ urlpatterns = [
|
||||
path('users/', views.UserListView.as_view(), name='user-list'),
|
||||
path('users/<int:pk>/', views.UserDetailView.as_view(), name='user-detail'),
|
||||
path('users/<int:pk>/status/', views.UserStatusView.as_view(), name='user-status'),
|
||||
# Phase 5: Events endpoints
|
||||
path('events/stats/', views.EventStatsView.as_view(), name='event-stats'),
|
||||
path('events/', views.EventListView.as_view(), name='event-list'),
|
||||
path('events/<int:pk>/', views.EventDetailView.as_view(), name='event-detail'),
|
||||
path('events/<int:pk>/moderate/', views.EventModerationView.as_view(), name='event-moderate'),
|
||||
]
|
||||
@@ -602,3 +602,118 @@ class UserStatusView(APIView):
|
||||
return Response({'error': 'action must be suspend, ban, or reinstate'}, status=400)
|
||||
u.save(update_fields=['is_active'])
|
||||
return Response({'id': str(u.id), 'status': _user_status(u)})
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Phase 5: Events API
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_EVENT_STATUS_MAP = {
|
||||
'live': 'live', 'published': 'published',
|
||||
'pending': 'published', 'created': 'draft',
|
||||
'flagged': 'flagged', 'cancelled': 'cancelled',
|
||||
'postponed': 'cancelled', 'completed': 'completed',
|
||||
}
|
||||
|
||||
|
||||
def _serialize_event(e):
|
||||
partner_name = ''
|
||||
if e.partner_id:
|
||||
try:
|
||||
partner_name = e.partner.name
|
||||
except Exception:
|
||||
partner_name = ''
|
||||
return {
|
||||
'id': str(e.id),
|
||||
'title': e.title or getattr(e, 'name', '') or '',
|
||||
'partnerId': str(e.partner_id) if e.partner_id else '',
|
||||
'partnerName': partner_name,
|
||||
'date': e.start_date.isoformat() if e.start_date else '',
|
||||
'status': _EVENT_STATUS_MAP.get(e.event_status, 'draft'),
|
||||
'ticketsSold': 0,
|
||||
'revenue': 0,
|
||||
'venueName': e.venue_name or '',
|
||||
'createdAt': e.created_date.isoformat() if e.created_date else '',
|
||||
'isFeatured': bool(e.is_featured),
|
||||
'isTopEvent': bool(e.is_top_event),
|
||||
}
|
||||
|
||||
|
||||
class EventStatsView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
from events.models import Event
|
||||
return Response({
|
||||
'total': Event.objects.count(),
|
||||
'live': Event.objects.filter(event_status='live').count(),
|
||||
'pending': Event.objects.filter(event_status__in=['pending', 'created']).count(),
|
||||
'flagged': Event.objects.filter(event_status='flagged').count(),
|
||||
'published': Event.objects.filter(event_status='published').count(),
|
||||
})
|
||||
|
||||
|
||||
class EventListView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
from events.models import Event
|
||||
from django.db.models import Q
|
||||
qs = Event.objects.select_related('partner').all()
|
||||
if s := request.GET.get('status'):
|
||||
reverse_map = {v: k for k, v in _EVENT_STATUS_MAP.items()}
|
||||
backend_status = reverse_map.get(s, s)
|
||||
qs = qs.filter(event_status=backend_status)
|
||||
if pid := request.GET.get('partner_id'):
|
||||
qs = qs.filter(partner_id=pid)
|
||||
if q := request.GET.get('search'):
|
||||
qs = qs.filter(
|
||||
Q(title__icontains=q) | Q(name__icontains=q) | Q(venue_name__icontains=q)
|
||||
)
|
||||
try:
|
||||
page = max(1, int(request.GET.get('page', 1)))
|
||||
page_size = min(100, int(request.GET.get('page_size', 20)))
|
||||
except (ValueError, TypeError):
|
||||
page, page_size = 1, 20
|
||||
total = qs.count()
|
||||
events = qs.order_by('-id')[(page - 1) * page_size: page * page_size]
|
||||
return Response({'count': total, 'results': [_serialize_event(e) for e in events]})
|
||||
|
||||
|
||||
class EventDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, pk):
|
||||
from events.models import Event
|
||||
from django.shortcuts import get_object_or_404
|
||||
e = get_object_or_404(Event.objects.select_related('partner'), pk=pk)
|
||||
return Response(_serialize_event(e))
|
||||
|
||||
|
||||
class EventModerationView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def patch(self, request, pk):
|
||||
from events.models import Event
|
||||
from django.shortcuts import get_object_or_404
|
||||
e = get_object_or_404(Event, pk=pk)
|
||||
action = request.data.get('action')
|
||||
if action == 'approve':
|
||||
e.event_status = 'published'
|
||||
e.save(update_fields=['event_status'])
|
||||
elif action == 'reject':
|
||||
e.event_status = 'cancelled'
|
||||
e.cancelled_reason = request.data.get('reason', '')
|
||||
e.save(update_fields=['event_status', 'cancelled_reason'])
|
||||
elif action == 'flag':
|
||||
e.event_status = 'flagged'
|
||||
e.save(update_fields=['event_status'])
|
||||
elif action == 'feature':
|
||||
e.is_featured = True
|
||||
e.save(update_fields=['is_featured'])
|
||||
elif action == 'unfeature':
|
||||
e.is_featured = False
|
||||
e.save(update_fields=['is_featured'])
|
||||
else:
|
||||
return Response({'error': 'Invalid action'}, status=400)
|
||||
e.refresh_from_db()
|
||||
return Response(_serialize_event(e))
|
||||
|
||||
Reference in New Issue
Block a user