from rest_framework import viewsets, status, filters from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.permissions import AllowAny from django.shortcuts import get_object_or_404 from django.db.models import Q from django.utils import timezone from .models import ( SupportTicket, TicketStatus, TicketPriority, TicketCategory, TicketMessage, KnowledgeBaseCategory, KnowledgeBaseArticle, SupportSettings ) from .serializers import ( SupportTicketSerializer, SupportTicketCreateSerializer, TicketStatusSerializer, TicketPrioritySerializer, TicketCategorySerializer, TicketMessageSerializer, TicketStatusCheckSerializer, KnowledgeBaseCategorySerializer, KnowledgeBaseArticleListSerializer, KnowledgeBaseArticleDetailSerializer, SupportSettingsSerializer ) class SupportTicketViewSet(viewsets.ModelViewSet): """ ViewSet for managing support tickets. Public endpoint for creating tickets and checking status. """ queryset = SupportTicket.objects.all() permission_classes = [AllowAny] filter_backends = [filters.SearchFilter, filters.OrderingFilter] search_fields = ['ticket_number', 'title', 'user_email', 'user_name'] ordering_fields = ['created_at', 'updated_at', 'priority'] ordering = ['-created_at'] def get_serializer_class(self): if self.action == 'create': return SupportTicketCreateSerializer return SupportTicketSerializer @action(detail=False, methods=['post'], url_path='check-status') def check_status(self, request): """ Check the status of a ticket by ticket number. POST /api/support/tickets/check-status/ Body: {"ticket_number": "TKT-20231015-XXXXX"} """ serializer = TicketStatusCheckSerializer(data=request.data) serializer.is_valid(raise_exception=True) ticket_number = serializer.validated_data['ticket_number'] try: ticket = SupportTicket.objects.get(ticket_number=ticket_number) ticket_serializer = SupportTicketSerializer(ticket) return Response(ticket_serializer.data) except SupportTicket.DoesNotExist: return Response( {'error': 'Ticket not found. Please check your ticket number.'}, status=status.HTTP_404_NOT_FOUND ) @action(detail=True, methods=['post'], url_path='add-message') def add_message(self, request, pk=None): """ Add a message to a ticket. POST /api/support/tickets/{id}/add-message/ Body: { "content": "Message content", "author_name": "User Name", "author_email": "user@example.com" } """ ticket = self.get_object() message_data = { 'ticket': ticket.id, 'content': request.data.get('content'), 'author_name': request.data.get('author_name', ticket.user_name), 'author_email': request.data.get('author_email', ticket.user_email), 'message_type': 'user_message' } serializer = TicketMessageSerializer(data=message_data) serializer.is_valid(raise_exception=True) serializer.save() # Update ticket's last activity ticket.last_activity = timezone.now() ticket.save() return Response(serializer.data, status=status.HTTP_201_CREATED) class TicketCategoryViewSet(viewsets.ReadOnlyModelViewSet): """ ViewSet for ticket categories. Public read-only access to categories. """ queryset = TicketCategory.objects.filter(is_active=True) serializer_class = TicketCategorySerializer permission_classes = [AllowAny] class TicketStatusViewSet(viewsets.ReadOnlyModelViewSet): """ ViewSet for ticket statuses. Public read-only access to statuses. """ queryset = TicketStatus.objects.filter(is_active=True) serializer_class = TicketStatusSerializer permission_classes = [AllowAny] class TicketPriorityViewSet(viewsets.ReadOnlyModelViewSet): """ ViewSet for ticket priorities. Public read-only access to priorities. """ queryset = TicketPriority.objects.filter(is_active=True) serializer_class = TicketPrioritySerializer permission_classes = [AllowAny] class KnowledgeBaseCategoryViewSet(viewsets.ReadOnlyModelViewSet): """ ViewSet for knowledge base categories. Public read-only access. """ queryset = KnowledgeBaseCategory.objects.filter(is_active=True) serializer_class = KnowledgeBaseCategorySerializer permission_classes = [AllowAny] lookup_field = 'slug' class KnowledgeBaseArticleViewSet(viewsets.ReadOnlyModelViewSet): """ ViewSet for knowledge base articles. Public read-only access to published articles. """ queryset = KnowledgeBaseArticle.objects.filter(is_published=True) permission_classes = [AllowAny] filter_backends = [filters.SearchFilter, filters.OrderingFilter] search_fields = ['title', 'content', 'summary', 'keywords'] ordering_fields = ['created_at', 'view_count', 'helpful_count'] ordering = ['-created_at'] lookup_field = 'slug' def get_serializer_class(self): if self.action == 'retrieve': return KnowledgeBaseArticleDetailSerializer return KnowledgeBaseArticleListSerializer def retrieve(self, request, *args, **kwargs): instance = self.get_object() # Increment view count instance.view_count += 1 instance.save(update_fields=['view_count']) serializer = self.get_serializer(instance) return Response(serializer.data) @action(detail=True, methods=['post'], url_path='mark-helpful') def mark_helpful(self, request, slug=None): """ Mark an article as helpful. POST /api/support/knowledge-base/{slug}/mark-helpful/ Body: {"helpful": true/false} """ article = self.get_object() is_helpful = request.data.get('helpful', True) if is_helpful: article.helpful_count += 1 else: article.not_helpful_count += 1 article.save() return Response({ 'helpful_count': article.helpful_count, 'not_helpful_count': article.not_helpful_count }) @action(detail=False, methods=['get'], url_path='featured') def featured(self, request): """ Get featured articles. GET /api/support/knowledge-base/featured/ """ featured_articles = self.queryset.filter(is_featured=True)[:6] serializer = self.get_serializer(featured_articles, many=True) return Response(serializer.data) @action(detail=False, methods=['get'], url_path='by-category/(?P[^/.]+)') def by_category(self, request, category_slug=None): """ Get articles by category slug. GET /api/support/knowledge-base/by-category/{category_slug}/ """ articles = self.queryset.filter(category__slug=category_slug) page = self.paginate_queryset(articles) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(articles, many=True) return Response(serializer.data) class SupportSettingsViewSet(viewsets.ReadOnlyModelViewSet): """ ViewSet for support settings. Public read-only access to active settings. """ queryset = SupportSettings.objects.filter(is_active=True) serializer_class = SupportSettingsSerializer permission_classes = [AllowAny] lookup_field = 'setting_name'