diff --git a/helpdesk/serializers.py b/helpdesk/serializers.py
index 1217350e..0f43d303 100644
--- a/helpdesk/serializers.py
+++ b/helpdesk/serializers.py
@@ -70,6 +70,46 @@ class DatatablesTicketSerializer(serializers.ModelSerializer):
return obj.kbitem.title if obj.kbitem else ""
+class PublicTicketListingSerializer(serializers.ModelSerializer):
+ """
+ A serializer to be used by the public API for listing tickets. Don't expose private fields here!
+ """
+ ticket = serializers.SerializerMethodField()
+ submitter = serializers.SerializerMethodField()
+ created = serializers.SerializerMethodField()
+ due_date = serializers.SerializerMethodField()
+ status = serializers.SerializerMethodField()
+ queue = serializers.SerializerMethodField()
+ kbitem = serializers.SerializerMethodField()
+
+ class Meta:
+ model = Ticket
+ # fields = '__all__'
+ fields = ('ticket', 'id', 'title', 'queue', 'status',
+ 'created', 'due_date', 'submitter', 'kbitem')
+
+ def get_queue(self, obj):
+ return {"title": obj.queue.title, "id": obj.queue.id}
+
+ def get_ticket(self, obj):
+ return str(obj.id) + " " + obj.ticket
+
+ def get_status(self, obj):
+ return obj.get_status
+
+ def get_created(self, obj):
+ return humanize.naturaltime(obj.created)
+
+ def get_due_date(self, obj):
+ return humanize.naturaltime(obj.due_date)
+
+ def get_submitter(self, obj):
+ return obj.submitter_email
+
+ def get_kbitem(self, obj):
+ return obj.kbitem.title if obj.kbitem else ""
+
+
class FollowUpAttachmentSerializer(serializers.ModelSerializer):
class Meta:
model = FollowUpAttachment
diff --git a/helpdesk/templates/helpdesk/my_tickets.html b/helpdesk/templates/helpdesk/my_tickets.html
new file mode 100644
index 00000000..2ec74f53
--- /dev/null
+++ b/helpdesk/templates/helpdesk/my_tickets.html
@@ -0,0 +1,69 @@
+{% extends "helpdesk/public_base.html" %}{% load i18n %}
+
+{% block helpdesk_body %}
+
{% trans "My Tickets" %}
+
+
+
+
+
+ Title |
+ Queue |
+ Status |
+ Created |
+ Due Date |
+ Submitter |
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/helpdesk/templates/helpdesk/navigation-sidebar.html b/helpdesk/templates/helpdesk/navigation-sidebar.html
index 07c062f5..e42815f8 100644
--- a/helpdesk/templates/helpdesk/navigation-sidebar.html
+++ b/helpdesk/templates/helpdesk/navigation-sidebar.html
@@ -68,6 +68,15 @@
{% trans "New Ticket" %}
+ {% if user.is_authenticated %}
+
+
+
+ {% trans "My Tickets" %}
+
+
+
+ {% endif %}
{% if helpdesk_settings.HELPDESK_KB_ENABLED %}
diff --git a/helpdesk/urls.py b/helpdesk/urls.py
index fbd8e0ce..96af9f23 100644
--- a/helpdesk/urls.py
+++ b/helpdesk/urls.py
@@ -14,7 +14,7 @@ from django.views.generic import TemplateView
from helpdesk import settings as helpdesk_settings
from helpdesk.decorators import helpdesk_staff_member_required, protect_view
from helpdesk.views import feeds, login, public, staff
-from helpdesk.views.api import CreateUserView, FollowUpAttachmentViewSet, FollowUpViewSet, TicketViewSet
+from helpdesk.views.api import CreateUserView, FollowUpAttachmentViewSet, FollowUpViewSet, TicketViewSet, UserTicketViewSet
from rest_framework.routers import DefaultRouter
@@ -154,6 +154,7 @@ if helpdesk_settings.HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET:
urlpatterns += [
path("", protect_view(public.Homepage.as_view()), name="home"),
+ path("tickets/my-tickets/", public.MyTickets.as_view(), name="my-tickets"),
path("tickets/submit/", public.create_ticket, name="submit"),
path(
"tickets/submit_iframe/",
@@ -199,15 +200,14 @@ urlpatterns += [
]
-# API is added to url conf based on the setting (False by default)
-if helpdesk_settings.HELPDESK_ACTIVATE_API_ENDPOINT:
- router = DefaultRouter()
- router.register(r"tickets", TicketViewSet, basename="ticket")
- router.register(r"followups", FollowUpViewSet, basename="followups")
- router.register(r"followups-attachments",
- FollowUpAttachmentViewSet, basename="followupattachments")
- router.register(r"users", CreateUserView, basename="user")
- urlpatterns += [re_path(r"^api/", include(router.urls))]
+router = DefaultRouter()
+router.register(r"tickets", TicketViewSet, basename="ticket")
+router.register(r"user_tickets", UserTicketViewSet, basename="user_tickets")
+router.register(r"followups", FollowUpViewSet, basename="followups")
+router.register(r"followups-attachments",
+ FollowUpAttachmentViewSet, basename="followupattachments")
+router.register(r"users", CreateUserView, basename="user")
+urlpatterns += [re_path(r"^api/", include(router.urls))]
urlpatterns += [
diff --git a/helpdesk/views/api.py b/helpdesk/views/api.py
index 7e3f0448..4970e28d 100644
--- a/helpdesk/views/api.py
+++ b/helpdesk/views/api.py
@@ -1,10 +1,29 @@
from django.contrib.auth import get_user_model
from helpdesk.models import FollowUp, FollowUpAttachment, Ticket
-from helpdesk.serializers import FollowUpAttachmentSerializer, FollowUpSerializer, TicketSerializer, UserSerializer
+from helpdesk.serializers import FollowUpAttachmentSerializer, FollowUpSerializer, TicketSerializer, UserSerializer, PublicTicketListingSerializer
from rest_framework import viewsets
from rest_framework.mixins import CreateModelMixin
from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import GenericViewSet
+from rest_framework.pagination import PageNumberPagination
+
+
+class ConservativePagination(PageNumberPagination):
+ page_size = 25
+ page_size_query_param = 'page_size'
+
+
+class UserTicketViewSet(viewsets.ReadOnlyModelViewSet):
+ """
+ A list of all the tickets submitted by the current user
+
+ The view is paginated by default
+ """
+ serializer_class = PublicTicketListingSerializer
+ pagination_class = ConservativePagination
+
+ def get_queryset(self):
+ return Ticket.objects.filter(submitter_email=self.request.user.email).order_by('-created')
class TicketViewSet(viewsets.ModelViewSet):
@@ -13,6 +32,7 @@ class TicketViewSet(viewsets.ModelViewSet):
"""
queryset = Ticket.objects.all()
serializer_class = TicketSerializer
+ pagination_class = ConservativePagination
permission_classes = [IsAdminUser]
def get_queryset(self):
@@ -30,12 +50,14 @@ class TicketViewSet(viewsets.ModelViewSet):
class FollowUpViewSet(viewsets.ModelViewSet):
queryset = FollowUp.objects.all()
serializer_class = FollowUpSerializer
+ pagination_class = ConservativePagination
permission_classes = [IsAdminUser]
class FollowUpAttachmentViewSet(viewsets.ModelViewSet):
queryset = FollowUpAttachment.objects.all()
serializer_class = FollowUpAttachmentSerializer
+ pagination_class = ConservativePagination
permission_classes = [IsAdminUser]
diff --git a/helpdesk/views/public.py b/helpdesk/views/public.py
index 57b87331..a323a093 100644
--- a/helpdesk/views/public.py
+++ b/helpdesk/views/public.py
@@ -208,12 +208,14 @@ class ViewTicket(TemplateView):
try:
queue, ticket_id = Ticket.queue_and_id_from_query(ticket_req)
+ if request.user.is_authenticated and request.user.email == email:
+ ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email)
if hasattr(settings, 'HELPDESK_VIEW_A_TICKET_PUBLIC') and settings.HELPDESK_VIEW_A_TICKET_PUBLIC:
ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email)
else:
ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email, secret_key__iexact=key)
except (ObjectDoesNotExist, ValueError):
- return search_for_ticket(request, _('Invalid ticket ID or e-mail address. Please try again.'))
+ return SearchForTicketView.as_view()(request, _('Invalid ticket ID or e-mail address. Please try again.'))
if 'close' in request.GET and ticket.status == Ticket.RESOLVED_STATUS:
from helpdesk.update_ticket import update_ticket
@@ -247,6 +249,17 @@ class ViewTicket(TemplateView):
return redirect_url
+class MyTickets(TemplateView):
+ template_name = 'helpdesk/my_tickets.html'
+
+ def get(self, request, *args, **kwargs):
+ if not request.user.is_authenticated:
+ return HttpResponseRedirect(reverse('helpdesk:login'))
+
+ context = self.get_context_data(**kwargs)
+ return self.render_to_response(context)
+
+
def change_language(request):
return_to = ''
if 'return_to' in request.GET: