implemented rest into home app

This commit is contained in:
Corban-Lee Jones 2024-01-12 19:25:45 +00:00
parent e0e16efb71
commit 362c8f0a16
8 changed files with 219 additions and 101 deletions

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.16 on 2024-01-12 16:04
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('authentication', '0001_initial'),
]
operations = [
migrations.RenameField(
model_name='department',
old_name='id',
new_name='uuid',
),
migrations.RenameField(
model_name='user',
old_name='id',
new_name='uuid',
),
]

View File

@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
import uuid
from uuid import uuid4
import os
from django.db import models
@ -23,11 +23,11 @@ class OverwriteStorage(FileSystemStorage):
@deconstructible
class IconPathGenerator:
def __call__(self, instance, filename: str) -> str:
return os.path.join("users", str(instance.id), "icon.webp")
return os.path.join("users", str(instance.uuid), "icon.webp")
class Department(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
uuid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
title = models.CharField(max_length=150)
icon = models.CharField(max_length=32, null=True, blank=True)
@ -35,12 +35,6 @@ class Department(models.Model):
def __str__(self):
return self.title
def serialize(self) -> dict:
return {
"title": self.title,
"icon": self.icon
}
class UserManager(BaseUserManager):
@ -70,7 +64,7 @@ class UserManager(BaseUserManager):
class User(AbstractBaseUser, PermissionsMixin):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
uuid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
icon = models.ImageField(
_("profile picture"),
@ -145,7 +139,7 @@ class User(AbstractBaseUser, PermissionsMixin):
verbose_name_plural = _('users')
def __str__(self):
return f"{self.id}{self.email}{self.formal_fullname}"
return f"{self.uuid}{self.email}{self.formal_fullname}"
def save(self, *args, **kwargs):
self.edit_timestamp = timezone.now()
@ -162,17 +156,3 @@ class User(AbstractBaseUser, PermissionsMixin):
@property
def formal_fullname(self) -> str:
return f"{self.surname}, {self.forename}"
def serialize(self) -> dict:
department = self.department.serialize() if self.department else None
return {
"id": self.id,
"icon": self.icon.url,
"email": self.email,
"forename": self.forename,
"surname": self.surname,
"department": department,
"create_timestamp": self.create_timestamp,
"edit_timestamp": self.edit_timestamp
}

View File

@ -1,7 +1,4 @@
# -*- encoding: utf-8 -*-
"""
Copyright (c) 2019 - present AppSeed.us
"""
from django.apps import AppConfig

View File

@ -0,0 +1,28 @@
# Generated by Django 3.2.16 on 2024-01-12 16:04
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('home', '0001_initial'),
]
operations = [
migrations.RenameField(
model_name='ticket',
old_name='id',
new_name='uuid',
),
migrations.RenameField(
model_name='ticketpriority',
old_name='id',
new_name='uuid',
),
migrations.RenameField(
model_name='tickettag',
old_name='id',
new_name='uuid',
),
]

View File

@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
import uuid
import bleach
from uuid import uuid4
from datetime import timedelta, datetime
from django.db import models
@ -11,7 +11,7 @@ from django.utils.translation import gettext_lazy as _
class TicketPriority(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
uuid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
title = models.CharField(max_length=32)
colour = models.CharField(max_length=7)
@ -20,17 +20,9 @@ class TicketPriority(models.Model):
def __str__(self):
return self.title
def serialize(self) -> dict:
return {
"id": self.id,
"title": self.title,
"colour": self.colour,
"backgroundcolour": self.backgroundcolour
}
class TicketTag(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
uuid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
title = models.CharField(max_length=32)
colour = models.CharField(max_length=7)
@ -39,66 +31,68 @@ class TicketTag(models.Model):
def __str__(self):
return self.title
def serialize(self) -> dict:
return {
"id": self.id,
"title": self.title,
"colour": self.colour,
"backgroundcolour": self.backgroundcolour
}
class Ticket(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
"""Represents a Ticket used to communicate issues or questions."""
uuid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
# Main Attributes
title = models.CharField(
_("title"),
verbose_name=_("title"),
help_text=_("An extremely short summary of the ticket subject."),
max_length=100,
help_text=_("An extremely short summary of the ticket subject.")
)
description = models.TextField(
_("description"),
verbose_name=_("description"),
help_text=_("Detailed description of the ticket subject."),
max_length=650,
help_text=_("Detailed description of the ticket subject.")
)
# Dirty Foreigers
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("author"),
help_text=_("The creator of the ticket."),
on_delete=models.CASCADE,
help_text=_("The creator of the ticket.")
)
priority = models.ForeignKey(
TicketPriority,
verbose_name=_("priority"),
help_text=_("The importance level of this ticket."),
on_delete=models.CASCADE,
help_text=_("The importance level of this ticket.")
)
tags = models.ManyToManyField(
TicketTag,
verbose_name=_("tags"),
help_text=_("Categories of the ticket."),
blank=True,
help_text=_("Categories of the ticket.")
)
# Timestamps
create_timestamp = models.DateTimeField(
_("Creation Date"),
verbose_name=_("Creation Date"),
help_text=_("When the user was created."),
editable=True,
default=timezone.now,
help_text=_("When the user was created.")
)
edit_timestamp = models.DateTimeField(
_("Last Edited"),
verbose_name=_("Last Edited"),
help_text=_("When the user was last edited."),
editable=True,
default=timezone.now,
help_text=_("When the user was last edited.")
)
def __str__(self):
return f"#{self.id}{self.title}{f' {self.author.department.title}' if self.author.department else ''} {self.author.formal_fullname}"
return f"#{self.uuid}{self.title}{f' {self.author.department.title}' if self.author.department else ''} {self.author.formal_fullname}"
def clean_description(self):
"""Sanitise the description as it may contain some allowed HTML tags."""
cleaned_description = bleach.clean(
self.description,
tags=[
@ -110,13 +104,14 @@ class Ticket(models.Model):
return cleaned_description
def save(self, *args, **kwargs):
"""Override the save method to clean the description and apply timestamps."""
self.description = self.clean_description()
# we must use the same datetime object, otherwise they wont match
now = timezone.now()
if self._state.adding: self.create_timestamp = now
self.edit_timestamp = now
if self._state.adding:
self.create_timestamp = now
super().save(*args, **kwargs)
@ -174,19 +169,3 @@ class Ticket(models.Model):
"""
return self.edit_timestamp if self.is_edited else self.create_timestamp
def serialize(self) -> dict:
return {
"id": self.id,
"title": self.title,
"description": self.description,
"author": self.author.serialize(),
"create_timestamp": self.create_timestamp,
"edit_timestamp": self.edit_timestamp,
"is_edited": self.is_edited,
"was_yesterday": self.was_yesterday,
"is_older_than_day": self.is_older_than_day,
"timestamp": self.timestamp,
"priority": self.priority.serialize(),
"tags": [tag.serialize() for tag in self.tags.all()]
}

View File

@ -1,7 +1,9 @@
# -*- encoding: utf-8 -*-
from django.urls import path, re_path, include
from apps.home import views
from .views import TicketView
urlpatterns = [
@ -11,7 +13,7 @@ urlpatterns = [
# Custom Dashboard
path('dashboard/', views.dashboard, name="dashboard"),
path('tickets/', include([
path('', views.tickets, name="tickets"),
path('', TicketView.as_view(), name="tickets"),
path('new/', views.new_ticket, name="ticket-new"),
path('get/', include([
path('one/', views.get_ticket, name="ticket-getone"),
@ -20,7 +22,7 @@ urlpatterns = [
])),
])),
# Matches any html file
re_path(r'^.*\.*', views.pages, name='pages'),
# # Matches any html file
# re_path(r'^.*\.*', views.pages, name='pages'),
]

View File

@ -11,7 +11,10 @@ from django.template import loader
from django.shortcuts import render
from django.urls import reverse
from django.contrib.auth import get_user_model
from django.views.generic import TemplateView
from django.utils.decorators import method_decorator
from apps.api.serializers import TicketSerializer
from ..authentication.models import Department
from .models import Ticket, TicketPriority, TicketTag
@ -21,6 +24,111 @@ def dashboard(request):
return render(request, "home/dashboard.html")
class TicketView(TemplateView):
template_name = "home/tickets.html"
@method_decorator(login_required)
def get(self, request):
tickets = Ticket.objects.all().order_by("-create_timestamp")
priorities = TicketPriority.objects.all()
tags = TicketTag.objects.all()
departments = Department.objects.all()
context = {
"tickets": tickets,
"priorities": priorities,
"tags": tags,
"departments": departments,
"dayago": datetime.now() - timedelta(hours=24)
}
return render(request, "home/tickets.html", context)
# @method_decorator(login_required)
# @require_POST
# def fetch_ticket(self, request) -> JsonResponse:
# ticket = Ticket.objects.get(id=request.POST.get("ticket_id"))
# context = {"ticket": ticket.serialize()}
# return JsonResponse(context)
# @method_decorator(login_required)
# @require_POST
# def fetch_tickets(self, request) -> JsonResponse:
# filters = json.loads(request.POST.get("filters", "{}"))
# queryset = Ticket.objects.all()
# for key, values in filters.items():
# print(key, values)
# for value in values:
# if value == "all": continue # don't apply a filter if we want all
# queryset = queryset.filter(**{key: [value]})
# tickets = queryset.order_by("-create_timestamp")
# context = {"tickets": [ticket.serialize() for ticket in tickets]}
# return JsonResponse(context)
# @method_decorator(login_required)
# @require_POST
# def fetch_filter_counts(self, request) -> JsonResponse:
# priorities = TicketPriority.objects.all()
# tags = TicketTag.objects.all()
# departments = Department.objects.all()
# tickets = Ticket.objects.all()
# context = {
# "priority_counts": {},
# "tag_counts": {},
# "department_counts": {},
# "ticket_count": tickets.count()
# }
# for priority in priorities:
# priority_count = tickets.filter(priority=priority).count()
# context["priority_counts"][str(priority.id)] = priority_count
# for tag in tags:
# tag_count = tickets.filter(tags__in=[tag]).count()
# context["tag_counts"][str(tag.id)] = tag_count
# for department in departments:
# department_count = tickets.filter(author__department=department).count()
# context["department_counts"][str(department.id)] = department_count
# return JsonResponse(context)
# @method_decorator(login_required)
# @require_POST
# def new_ticket(self, request) -> JsonResponse:
# getall = lambda *keys: [request.POST.get(key) for key in keys]
# getlist = lambda key: request.POST.getlist(key)
# title, description, author_id, priority_id = getall(
# "title", "description", "author_id", "priority_id"
# )
# tag_ids = getlist("tag_ids[]")
# author = get_user_model().objects.get(id=author_id)
# priority = TicketPriority.objects.get(id=priority_id)
# tags = [
# tag for tag in TicketTag.objects.filter(id__in=tag_ids)
# ]
# ticket = Ticket.objects.create(
# title=title,
# description=description,
# author=author,
# priority=priority,
# )
# ticket.tags.set(tags)
# return JsonResponse({"success": "ticket created successfully"})
@login_required()
def tickets(request):
tickets = Ticket.objects.all().order_by("-create_timestamp")
@ -42,8 +150,9 @@ def tickets(request):
@login_required
@require_POST
def get_ticket(request):
ticket = Ticket.objects.get(id=request.POST.get("ticket_id"))
data = {"ticket": ticket.serialize()}
ticket = Ticket.objects.get(uuid=request.POST.get("ticket_uuid"))
serializer = TicketSerializer(ticket)
data = {"ticket": serializer.data}
return JsonResponse(data)
@ -62,8 +171,9 @@ def get_tickets(request):
queryset = queryset.filter(**{key: [value]})
tickets = queryset.order_by("-create_timestamp")
serializer = TicketSerializer(tickets, many=True)
data = {"tickets": [ticket.serialize() for ticket in tickets]}
data = {"tickets": serializer.data}
return JsonResponse(data)
@ -86,13 +196,13 @@ def get_filter_counts(request):
}
for priority in priorities:
data["priority_counts"][str(priority.id)] = tickets.filter(priority=priority).count()
data["priority_counts"][str(priority.uuid)] = tickets.filter(priority=priority).count()
for tag in tags:
data["tag_counts"][str(tag.id)] = tickets.filter(tags__in=[tag]).count()
data["tag_counts"][str(tag.uuid)] = tickets.filter(tags__in=[tag]).count()
for department in departments:
data["department_counts"][str(department.id)] = tickets.filter(author__department=department).count()
data["department_counts"][str(department.uuid)] = tickets.filter(author__department=department).count()
return JsonResponse(data)
@ -154,7 +264,6 @@ def pages(request):
return HttpResponse(html_template.render(context, request))
except template.TemplateDoesNotExist:
html_template = loader.get_template('home/page-404.html')
return HttpResponse(html_template.render(context, request))

View File

@ -46,10 +46,10 @@
{% for priority in priorities %}
<li class="nav-item filter-priority">
<label for="filterPriority-{{ priority.id }}" class="nav-link c-grey-800 cH-blue-500 actived">
<label for="filterPriority-{{ priority.uuid }}" class="nav-link c-grey-800 cH-blue-500 actived">
<div class="peers ai-c jc-sb">
<div class="peer peer-greed">
<input type="radio" id="filterPriority-{{ priority.id }}" name="filterPriorities" class="form-check-input me-2" value="{{ priority.id }}">
<input type="radio" id="filterPriority-{{ priority.uuid }}" name="filterPriorities" class="form-check-input me-2" value="{{ priority.uuid }}">
<span>{{ priority.title }}</span>
</div>
<div class="peer">
@ -72,10 +72,10 @@
{% for tag in tags %}
<li class="nav-item filter-tag">
<label for="filterTag-{{ tag.id }}" class="nav-link c-grey-800 cH-blue-500 actived">
<label for="filterTag-{{ tag.uuid }}" class="nav-link c-grey-800 cH-blue-500 actived">
<div class="peers ai-c jc-sb">
<div class="peer peer-greed">
<input type="checkbox" id="filterTag-{{ tag.id }}" class="form-check-input me-2" value="{{ tag.id }}">
<input type="checkbox" id="filterTag-{{ tag.uuid }}" class="form-check-input me-2" value="{{ tag.uuid }}">
<span>{{ tag.title }}</span>
</div>
<div class="peer">
@ -98,10 +98,10 @@
{% for department in departments %}
<li class="nav-item filter-department">
<label for="filterDepartment-{{ department.id }}" class="nav-link c-grey-800 cH-blue-500 actived">
<label for="filterDepartment-{{ department.uuid }}" class="nav-link c-grey-800 cH-blue-500 actived">
<div class="peers ai-c jc-sb">
<div class="peer peer-greed">
<input type="checkbox" id="filterDepartment-{{ department.id }}" class="form-check-input me-2" value="{{ department.id }}">
<input type="checkbox" id="filterDepartment-{{ department.uuid }}" class="form-check-input me-2" value="{{ department.uuid }}">
<span>{{ department.title }}</span>
</div>
<div class="peer">
@ -319,7 +319,7 @@
<label for="newPriority" class="form-label">Priority</label>
<select name="newPriority" id="newPriority" class="select-2">
{% for priority in priorities %}
<option value="{{ priority.id }}">{{ priority.title }}</option>
<option value="{{ priority.uuid }}">{{ priority.title }}</option>
{% endfor %}
</select>
<small class="text-muted">How important is this ticket?</small>
@ -328,7 +328,7 @@
<label for="newTags" class="form-label">Tags</label>
<select name="newTags" id="newTags" class="select-2" multiple="multiple">
{% for tag in tags %}
<option value="{{ tag.id }}">{{ tag.title }}</option>
<option value="{{ tag.uuid }}">{{ tag.title }}</option>
{% endfor %}
</select>
<small class="text-muted">Use tags to categorize this ticket.</small>
@ -457,7 +457,7 @@
csrfmiddlewaretoken: "{{ csrf_token }}",
title: $("#newTitle").val(),
description: editor.getData(),
author_id: "{{ request.user.id }}",
author_id: "{{ request.user.uuid }}",
priority_id: $("#newPriority").val(),
tag_ids: $("#newTags").val()
},
@ -553,7 +553,7 @@
}
var item = $(`
<div class="email-list-item peers fxw-nw p-20 bdB bgcH-grey-100 cur-p" data-ticket-id="${ticket.id}" data-author-icon="${ticket.author.icon}">
<div class="email-list-item peers fxw-nw p-20 bdB bgcH-grey-100 cur-p" data-ticket-id="${ticket.uuid}" data-author-icon="${ticket.author.icon}">
<div class="peer mR-10">
<img src="${ticket.author.icon}" alt="" class="w-2r h-2r bdrs-50p me-2" style="object-fit: cover;">
</div>
@ -626,7 +626,7 @@
dataType: 'json',
data: {
csrfmiddlewaretoken: '{{ csrf_token }}',
ticket_id: ticketID
ticket_uuid: ticketID
},
success: function (data) {
console.log(JSON.stringify(data, null, 4));