217 lines
7.6 KiB
Python
217 lines
7.6 KiB
Python
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<category_slug>[^/.]+)')
|
|
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'
|