149 lines
4.5 KiB
Python

# -*- encoding: utf-8 -*-
import logging
from typing import Any
from django.db.models import Q
from django.http import HttpRequest
from django.core.cache import cache
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
from django.core.exceptions import ValidationError
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status, permissions
from rest_framework.pagination import PageNumberPagination
from apps.home.models import Ticket, TicketPriority, TicketTag
from apps.authentication.models import Department
from .serializers import (
TicketSerializer, TicketTagSerializer, TicketPrioritySerializer,
UserSerializer
)
log = logging.getLogger(__name__)
def respond_error(error: Exception, status: Any) -> Response:
logging.error(error)
return Response({
"detail": str(error),
"error": error.__class__.__name__
}, status=status)
class TicketPaginiation(PageNumberPagination):
page_size = 25
page_size_query_param = "page_size"
max_page_size = 100
class TicketListApiView(APIView):
permission_classes = [permissions.IsAuthenticated]
pagination_class = TicketPaginiation
ALLOWED_FILTERS = ("uuid__in", "priority__in", "tags__in", "author__department__in", "title__contains")
MATCHER_MAP = {
"contains": lambda k, v: {k: v[0]},
"in": lambda k, v: {k: v}
}
# @method_decorator(cache_page(60 * 5))
def get(self, request: HttpRequest) -> Response:
"""Returns a response containing tickets matching the given filters."""
try:
return self._get_tickets(request)
except KeyError as error:
return respond_error(error, status.HTTP_400_BAD_REQUEST)
except ValidationError as error:
return respond_error(error, status.HTTP_400_BAD_REQUEST)
def post(self, request):
"""Create a new ticket"""
serializer = TicketSerializer(data={
})
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def _get_tickets(self, request: HttpRequest) -> Response:
"""Returns a response containing tickets matching the given filters.
Parameters
----------
request : HttpRequest
The request containing the filters.
Returns
-------
Response
A response containing the tickets data.
Raises
------
KeyError
If any given filter key isn't in `self.ALLOWED_FILTERS`.
ValidationError
If any ValidationErrors are raised by Django while applying filters.
"""
queryset = Ticket.objects.all()
for key, values in request.GET.lists():
key = key.removesuffix("[]")
if key not in self.ALLOWED_FILTERS:
raise KeyError(key)
if "all" in values:
continue
if not key.endswith("__in"):
values = values[0]
filter_kwargs = {key: values}
queryset = queryset.filter(Q(**filter_kwargs))
tickets = queryset.order_by("-create_timestamp")
serializer = TicketSerializer(tickets, many=True)
response_data = serializer.data
log.debug("Query successful showing %s results", tickets.count())
return Response(response_data, status=status.HTTP_200_OK)
class FilterCountApiView(APIView):
permission_classes = [permissions.IsAuthenticated]
@method_decorator(cache_page(60 * 5))
def get(self, request):
priorities = TicketPriority.objects.all()
tags = TicketTag.objects.all()
departments = Department.objects.all()
tickets = Ticket.objects.all()
data = {
"priority_counts": {},
"tag_counts": {},
"department_counts": {},
"ticket_count": tickets.count()
}
for priority in priorities:
data["priority_counts"][str(priority.uuid)] = tickets.filter(priority=priority).count()
for tag in tags:
data["tag_counts"][str(tag.uuid)] = tickets.filter(tags__in=[tag]).count()
for department in departments:
data["department_counts"][str(department.uuid)] = tickets.filter(author__department=department).count()
return Response(data, status=status.HTTP_200_OK)