Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature archive #2

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 46 additions & 12 deletions techsupport/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,8 @@ class Meta:
verbose_name_plural = "subcategories"


class SupportTicket(BaseModel):
"""Model representing a support ticket submitted by a coach."""

class SupportTicket(models.Model):
"""Model representing a support ticket."""
class Status(models.TextChoices):
OPEN = "Open", _("Open")
IN_PROGRESS = "In Progress", _("In Progress")
Expand All @@ -302,7 +301,7 @@ class Priority(models.TextChoices):
verbose_name=_("ticket number"), unique=True, editable=False
)
date_submitted = models.DateTimeField(
verbose_name=_("date submitted"), default=now, editable=False
verbose_name=_("date submitted"), default=timezone.now, editable=False
)
date_resolved = models.DateTimeField(
verbose_name=_("date resolved"), null=True, blank=True
Expand Down Expand Up @@ -363,6 +362,7 @@ class Priority(models.TextChoices):
blank=True,
)
resolution_notes = models.TextField(blank=True)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

assigned_to = models.ForeignKey(
User,
Expand All @@ -372,14 +372,14 @@ class Priority(models.TextChoices):
blank=True,
related_name="assigned_tickets",
)

archived = models.BooleanField(default=False, verbose_name=_("archived"))
date_archived = models.DateTimeField(
null=True, blank=True, verbose_name=_("date archived")
)

def save(self, *args, **kwargs):
"""
Override the save method to set the ticket number and support description.

Args:
*args: Arguments passed to the superclass method.
**kwargs: Keyword arguments passed to the superclass method.
Override the save method to auto-generate ticket number and title if not provided.
"""
if not self.ticket_number:
max_ticket_number = SupportTicket.objects.aggregate(
Expand All @@ -393,8 +393,7 @@ def save(self, *args, **kwargs):

def ticket_age(self):
"""
Method that returns the difference between the current time and the time
the support ticket was submitted.
Calculate the age of the ticket based on submission time.
"""
now = timezone.now()
age = now - self.date_submitted
Expand All @@ -414,3 +413,38 @@ def ticket_age(self):
return f"{hours} hrs ago"
else:
return f"{minutes} mins ago"

def archive(self):
"""Archive the ticket if it is resolved."""
if self.status == SupportTicket.Status.RESOLVED:
self.status = SupportTicket.Status.CLOSED
self.archived = True
self.date_archived = timezone.now()
self.save()
return True
return False

def unarchive(self):
"""
Unarchive the ticket if it is closed or resolved
"""
if self.can_be_unarchived():
self.status = SupportTicket.Status.OPEN # Set the status to 'OPEN' when unarchiving
self.archived = False
self.date_archived = None
self.save()
return True
return False

def can_be_archived(self):
"""
Check if the ticket can be archived
"""
return self.status == SupportTicket.Status.RESOLVED

def can_be_unarchived(self):
"""
Check if the ticket can be unarchived
"""
return self.status in [SupportTicket.Status.CLOSED, SupportTicket.Status.RESOLVED]

37 changes: 25 additions & 12 deletions techsupport/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ <h5 class="d-none d-md-block"><strong>Technical Support</strong></h5>
<i class='bi bi-person-square nav_icon'></i>
<span class="profile">Profile</span>
</a>
{% if user.is_superuser or user.is_admin %}
<a href="{% url 'archive' %}" class="nav_link">
<i class='bi bi-archive nav_icon'></i>
<span class="archive">Archive</span>
</a>
{% endif %}
</div>
</div>

Expand All @@ -75,20 +81,27 @@ <h5 class="d-none d-md-block"><strong>Technical Support</strong></h5>
</nav>
</div>

<!-- Display Messages -->
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-8">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} text-center fade-out" style="animation: fadeOut 4.5s forwards;" role="alert">
{{ message }}
<!-- Display Messages -->
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-8">
{% if messages %}
{% for message in messages %}
{% if message.tags == 'error' %}
<div class="alert alert-danger text-center fade-out" role="alert" style="animation: fadeOut 4.5s forwards;">
<i class="bi bi-exclamation-circle"></i> {{ message }}
</div>
{% endfor %}
{% endif %}
</div>
{% else %}
<div class="alert alert-{{ message.tags }} text-center fade-out" role="alert" style="animation: fadeOut 4.5s forwards;">
<i class="bi bi-check-circle"></i> {{ message }}
</div>
{% endif %}
{% endfor %}
{% endif %}

</div>
</div>
</div>
</div>

<!-- CSS Animation -->
<style>
Expand Down
49 changes: 31 additions & 18 deletions techsupport/templates/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ <h6 class="text-muted fw-normal fs-6" title="Resolved">Resolved</h6>
</div>
</td>
<td class="text-center">
<div class="d-flex justify-content-start align-items-center text-truncate">{{ ticket.centre }}</div>
<div class="d-flex justify-content-start align-items-center text-truncate">{{ ticket.centre.acronym }}</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-start text-truncate">
Expand Down Expand Up @@ -237,23 +237,36 @@ <h6 class="text-muted fw-normal fs-6" title="Resolved">Resolved</h6>
{{ ticket.ticket_age }}
</div>
</td>
<!-- Only visible to technician or above -->
{% if user_role == 'super_admin' or user_role == 'admin' or user_role == 'technician'%}
{% if ticket.status == 'In Progress' or ticket.status == 'Resolved' %}
<td class="text-center">
<div class="d-grid">
<a href="{% url 'ticket_details' ticket.id %}" class="btn btn-secondary btn-block">Details</a>
</div>
</td>
{% else %}
<td class="text-center">
<div class="d-grid">
<a href="{% url 'ticket_details' ticket.id %}" class="btn bg-success btn-block d-md-none text-white">Take</a>
<a href="{% url 'ticket_details' ticket.id %}" class="btn bg-success btn-block d-none d-md-block text-white">Take Ticket</a>
</div>
</td>
{% endif %}
{% endif %}
<!-- Only visible to technician or above -->
{% if user_role == 'super_admin' or user_role == 'admin' or user_role == 'technician' %}
{% if ticket.status == 'In Progress' or ticket.status == 'Resolved' %}
<td class="text-center">
<div class="d-flex">
<a href="{% url 'ticket_details' ticket.id %}" class="btn btn-secondary mr-1">
<i class="bi bi-info-circle"></i>
</a>
{% if user_role == 'super_admin' or user_role == 'admin' %}
<a href="{% url 'archive_ticket' ticket.id %}" class="btn btn-danger ml-1">
<i class="bi bi-archive"></i>
</a>
{% endif %}
</div>
</td>
{% else %}
<td class="text-center">
<div class="d-flex">
<a href="{% url 'ticket_details' ticket.id %}" class="btn bg-success text-white mr-1">
<i class="bi bi-check"></i>
</a>
{% if user_role == 'super_admin' or user_role == 'admin' %}
<a href="{% url 'archive_ticket' ticket.id %}" class="btn btn-danger ml-1">
<i class="bi bi-archive"></i>
</a>
{% endif %}
</div>
</td>
{% endif %}
{% endif %}
</tr>
{% endfor %}
{% else %}
Expand Down
4 changes: 2 additions & 2 deletions techsupport/templates/support_ticket/all_tickets.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h6 class="card-title">
</h6>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered text-truncate">
<table class="table table-striped table-borderless text-truncate">
<thead>
<tr>
<th class="text-start">#</th>
Expand All @@ -38,7 +38,7 @@ <h6 class="card-title">
</div>
</td>
<td>
<div class="d-flex align-items-center justify-content-start">{{ ticket.centre }}
<div class="d-flex align-items-center justify-content-start">{{ ticket.centre.acronym }}
</div>
</td>
<td>
Expand Down
97 changes: 97 additions & 0 deletions techsupport/templates/support_ticket/archive.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{% extends 'base.html' %}
{% load static %}

{% block content %}
<div class="container-fluid mt-5">
<div class="row justify-content-center">
<div class="col-md-10">
<!-- Archived Tickets Table -->
<div class="card border-0 shadow mb-4">
<div class="card-header bg-success text-white text-center rounded-top">
<h6 class="card-title">
<i class="bi bi-journal-plus me-2"></i>
<span class="mr-2"></span><strong>Archived Tickets</strong>
</h6>
</div>
<div class="table-responsive">
<table class="table table-striped table-borderless text-truncate">
<thead>
<tr>
<th class="text-start">#</th>
<th class="text-start">Title</th>
<th class="text-start">Centre</th>
{% comment %} <th class="text-start">Status</th> {% endcomment %}
{% comment %} <th class="text-start">Priority</th> {% endcomment %}
<th class="text-start">Ticket Age</th>
<th class="text-start">By</th>
<th class="text-start">Actions</th>
</tr>
</thead>
<tbody>
{% for ticket in archived_tickets %}
<tr>
<td>{{ ticket.ticket_number }}</td>
<td class="text-start">
<div class="d-flex align-items-center justify-content-start">
<a href="{% url 'ticket_details' ticket.id %}" class="text-truncate"
data-bs-toggle="tooltip" data-bs-placement="top"
title="{{ ticket.title }}">{{ ticket.title }}</a>
</div>
</td>
<td>
<div class="d-flex align-items-center justify-content-start">{{ ticket.centre.acronym }}
</div>
</td>
{% comment %} <td>
<div class="d-flex align-items-center justify-content-start">
{% if ticket.status == 'Closed' %}
<i class="bi bi-archive me-1"></i><span class="mr-2"></span>Closed
{% else %}
<!-- This block will be empty for tickets that are not archived -->
{% endif %}
</div>
</td> {% endcomment %}
{% comment %} <td>
<div class="d-flex align-items-center justify-content-start">
{% if ticket.priority == 'High' %}
<i class="bi bi-exclamation-triangle text-danger me-1"></i><span
class="mr-2"></span>
{% elif ticket.priority == 'Medium' %}
<i class="bi bi-exclamation-triangle text-warning me-1"></i><span
class="mr-2"></span>
{% else %}
<i class="bi bi-exclamation-triangle text-success me-1"></i><span
class="mr-2"></span>
{% endif %}
{{ ticket.priority }}
</div>
</td> {% endcomment %}
<td>{{ ticket.ticket_age }}</td>
<td>
{% if ticket.submitted_by == user %}
You
{% else %}
{{ ticket.submitted_by.username }}
{% endif %}
</td>
<td>
<a href="{% url 'unarchive_ticket' ticket.id %}" class="btn bg-success ml-1">
<i class="bi bi-arrow-counterclockwise text-white"></i>
</a>
</td>
</tr>
{% empty %}
<tr>
<!-- No Tickets Found -->
<td colspan="8" class="text-center">No archived tickets found.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

6 changes: 5 additions & 1 deletion techsupport/templatetags/custom_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ def add_class(field, class_name):
field.field.widget.attrs['class'] += f' {class_name}'
else:
field.field.widget.attrs['class'] = class_name
return field
return field

@register.filter
def filter_not_archived(tickets):
return tickets.filter(archived=False)
9 changes: 9 additions & 0 deletions techsupport/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.urls import path
from uuid import UUID
from .views import (
user_login,
user_logout,
Expand All @@ -14,6 +15,9 @@
tickets_in_progress,
get_subcategories,
export_tickets_csv,
archive,
archive_ticket,
unarchive_ticket,
)
from django.conf import settings
from django.conf.urls.static import static
Expand All @@ -34,6 +38,11 @@
path("resolved_tickets/", resolved_tickets, name="resolved_tickets"),
path("tickets_in_progress/", tickets_in_progress, name="tickets_in_progress"),
path("get_subcategories/", get_subcategories, name="get_subcategories"),
path("archive/", archive, name="archive"),
path('archive_ticket/<uuid:ticket_id>/', archive_ticket, name='archive_ticket'),
path('unarchive_ticket/<uuid:ticket_id>/', unarchive_ticket, name='unarchive_ticket'),


]

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Loading