from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required from django.shortcuts import get_object_or_404 from .models import Ticket, Template, FileAttachment from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.db.models import Q from .forms import CommentForm, TicketForm, TemplateForm, TeamAssignmentForm, CategoryAssignmentForm from django.http import Http404, FileResponse from django.conf import settings import os @login_required def show_tickets(request): tickets = Ticket.get_open_tickets(request.user).order_by("priority", "-updated_at") return render(request, "ticketing/tickets.html", {"tickets": tickets}) @login_required def show_tickets_history(request): qs = Ticket.get_closed_tickets(request.user).order_by("priority", "-updated_at") per_page = int(request.GET.get("per_page") or 20) paginator = Paginator(qs, per_page) page_number = request.GET.get("page") or 1 try: page_obj = paginator.page(page_number) except PageNotAnInteger: page_obj = paginator.page(1) except EmptyPage: # Show last page if page is out of range page_obj = paginator.page(paginator.num_pages) context = { "tickets": page_obj.object_list, "page_obj": page_obj, "paginator": paginator, "is_paginated": page_obj.paginator.num_pages > 1, "per_page": per_page, } print(paginator, page_obj) return render(request, "ticketing/tickets_history.html", context) @login_required def show_ticket(request, ticket_id): ticket = get_object_or_404(Ticket, pk=ticket_id) can_edit = ticket.can_edit(request.user) # comment_templates = Template.objects.filter(category=ticket.category) if not ticket.can_open(request.user): return redirect("all_tickets") form, template_form, team_assignment_form, category_assignment_form = CommentForm( ), TemplateForm(), TeamAssignmentForm(), CategoryAssignmentForm() if request.method == "POST": if 'apply_template' in request.POST and can_edit: template_form = TemplateForm(request.POST) if template_form.is_valid(): template = template_form.cleaned_data["template_select"] form = CommentForm(initial={"text": template.content}) elif 'assign_to_team' in request.POST and can_edit: team_assignment_form = TeamAssignmentForm(request.POST) if team_assignment_form.is_valid(): ticket.assign_to_team( team_assignment_form.cleaned_data["team_select"]) elif 'assign_to_category' in request.POST and can_edit: category_assignment_form = CategoryAssignmentForm(request.POST) if category_assignment_form.is_valid(): ticket.category = category_assignment_form.cleaned_data["category_select"] ticket.save() elif 'assign_self' in request.POST and can_edit: ticket.assigned_to = request.user ticket.save() elif 'reopen_ticket' in request.POST and can_edit: ticket.status = Ticket.Status.IN_PROGRESS ticket.save() else: form = CommentForm(request.POST, request.FILES) if form.is_valid(): ticket.comment_set.create( user=request.user, ticket=ticket, text=form.cleaned_data["text"], is_only_for_staff=form.cleaned_data["hidden_from_client"] ) # Add attachments if form.cleaned_data["attachments"]: for file in form.cleaned_data["attachments"]: ticket.fileattachment_set.create(file=file) if 'close' in request.POST and can_edit: ticket.close_ticket() return redirect("ticket_detail", ticket_id=ticket.id) comments = ticket.comment_set.all() context = { "ticket": ticket, "comments": comments, "attachments": ticket.fileattachment_set.all(), "form": form, "template_form": template_form, "team_assignment_form": team_assignment_form, "category_assignment_form": category_assignment_form, "can_edit": can_edit } return render(request, "ticketing/ticket_detail.html", context) @login_required def create_ticket(request): has_closed_tickets = Ticket.objects.filter( user=request.user, status=Ticket.Status.CLOSED).exists() if request.method == "POST": form = TicketForm(request.user, request.POST, request.FILES) if form.is_valid(): ticket = form.save(commit=False) ticket.user = request.user ticket.save() # Add attachments if form.cleaned_data["attachments"]: for file in form.cleaned_data["attachments"]: ticket.fileattachment_set.create(file=file) return redirect("ticket_detail", ticket_id=ticket.id) else: form = TicketForm(request.user) return render(request, "ticketing/create_ticket.html", {"form": form, "has_closed_tickets": has_closed_tickets}) @login_required def dashboard(request): tickets = Ticket.objects.all().order_by("-created_at") open_tickets = tickets.filter(status=Ticket.Status.OPEN) in_progress_tickets = tickets.filter(status=Ticket.Status.IN_PROGRESS) closed_tickets = tickets.filter(status=Ticket.Status.CLOSED) return render(request, "ticketing/dashboard.html", {"tickets": tickets, "open_tickets": open_tickets, "in_progress_tickets": in_progress_tickets, "closed_tickets": closed_tickets}) @login_required def download_attachment(request, attachment_id): """ View that checks if the user has permission to access the ticket before serving the file. """ attachment = get_object_or_404(FileAttachment, pk=attachment_id) ticket = attachment.ticket if not ticket.can_open(request.user): raise Http404("File not found") if not attachment.file: raise Http404("File not found") try: file = attachment.file.open('rb') response = FileResponse(file, content_type='application/octet-stream') filename = os.path.basename(attachment.file.name) response['Content-Disposition'] = f'inline; filename="{filename}"' return response except (ValueError, IOError, OSError): # backwards compatibility try: old_path = os.path.join(settings.MEDIA_ROOT, attachment.file.name) if os.path.exists(old_path): file = open(old_path, 'rb') response = FileResponse(file, content_type='application/octet-stream') filename = os.path.basename(attachment.file.name) response['Content-Disposition'] = f'inline; filename="{filename}"' return response except (ValueError, IOError, OSError): pass raise Http404("File not found")