149 lines
4.5 KiB
Python
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) |