# -*- 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)