working on ticket js

This commit is contained in:
Corban-Lee Jones 2024-01-05 00:12:13 +00:00
parent d9ecd692ef
commit ff4c71dc54
8 changed files with 168 additions and 33 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.16 on 2024-01-04 22:15
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('authentication', '0003_auto_20240104_1447'),
]
operations = [
migrations.AlterModelManagers(
name='user',
managers=[
],
),
]

View File

@ -3,11 +3,34 @@
import uuid import uuid
from django.db import models from django.db import models
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser, BaseUserManager
# default user profile image class UserManager(BaseUserManager):
# https://st3.depositphotos.com/9998432/13335/v/450/depositphotos_133352156-stock-illustration-default-placeholder-profile-icon.jpg
def create_user(self, email: str, name: str, password: str=None, **extra_fields):
if not email:
raise ValueError("Please provide an email address")
email = self.normalize_email(email)
user = self.model(email=email, name=name, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email: str, name: str, password: str, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("is_active", True)
if not extra_fields.get("is_staff"):
raise ValueError("Superuser must have is_staff=True")
if not extra_fields.get("is_superuser"):
raise ValueError("Superuser must have is_superuser=True")
return self.create_user(email, name, password, **extra_fields)
class User(AbstractUser): class User(AbstractUser):
@ -17,7 +40,17 @@ class User(AbstractUser):
email = models.EmailField(unique=True) email = models.EmailField(unique=True)
USERNAME_FIELD = "email" USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["id", "icon", "name"] REQUIRED_FIELDS = ["name"]
objects = UserManager()
def __str__(self): def __str__(self):
return self.name return self.name
def serialize(self) -> dict:
return {
"id": self.id,
"icon": self.icon.url,
"name": self.name,
"email": self.email
}

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.16 on 2024-01-04 23:51
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('home', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='ticket',
name='id',
field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False),
),
]

View File

@ -1,5 +1,7 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
import uuid
import bleach
from datetime import timedelta, datetime from datetime import timedelta, datetime
from django.db import models from django.db import models
@ -18,6 +20,7 @@ class TicketTag(models.Model):
class Ticket(models.Model): class Ticket(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=60) title = models.CharField(max_length=60)
description = models.TextField(max_length=650) description = models.TextField(max_length=650)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
@ -27,6 +30,18 @@ class Ticket(models.Model):
def __str__(self): def __str__(self):
return f"#{self.id}{self.title}{self.author}" return f"#{self.id}{self.title}{self.author}"
def clean_description(self):
cleaned_description = bleach.clean(
self.description,
tags=['b', 'i', 'u', 'p', 'br', 'a', 'h3', 'h4', 'h5', 'h6'],
attributes={'a': ['href', 'title']}
)
return cleaned_description
def save(self, *args, **kwargs):
self.description = self.clean_description()
super().save(*args, **kwargs)
@property @property
def is_edited(self) -> bool: def is_edited(self) -> bool:
"""Returns boolean if the ticket is believed to have been edited. """Returns boolean if the ticket is believed to have been edited.
@ -65,3 +80,16 @@ class Ticket(models.Model):
""" """
return self.edit_timestamp if self.is_edited else self.create_timestamp 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,
"is_older_than_day": self.is_older_than_day,
"timestamp": self.timestamp
}

View File

@ -1,7 +1,4 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
"""
Copyright (c) 2019 - present AppSeed.us
"""
from django.urls import path, re_path, include from django.urls import path, re_path, include
from apps.home import views from apps.home import views
@ -16,6 +13,7 @@ urlpatterns = [
path('tickets/', include([ path('tickets/', include([
path('', views.tickets, name="tickets"), path('', views.tickets, name="tickets"),
path('new/', views.new_ticket, name="ticket-new"), path('new/', views.new_ticket, name="ticket-new"),
path('get/<int:ticket_id>', views.get_ticket, name="ticket-get"),
])), ])),
# Matches any html file # Matches any html file

View File

@ -4,10 +4,12 @@ from datetime import timedelta, datetime
from django import template from django import template
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect from django.views.decorators.http import require_POST
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.template import loader from django.template import loader
from django.shortcuts import render from django.shortcuts import render
from django.urls import reverse from django.urls import reverse
from django.forms.models import model_to_dict
from .models import Ticket from .models import Ticket
@ -28,8 +30,11 @@ def tickets(request):
return render(request, "home/tickets.html", context) return render(request, "home/tickets.html", context)
@require_POST
def get_ticket(request, ticket_id: int): def get_ticket(request, ticket_id: int):
ticket = Ticket.objects.get(id=ticket_id) ticket = Ticket.objects.get(id=ticket_id)
data = {"ticket": ticket.serialize()}
return JsonResponse(data)

View File

@ -214,7 +214,7 @@
<div class="peer"> <div class="peer">
<small class="ticket-timestamp"> <small class="ticket-timestamp">
{% if ticket.is_older_than_day %} {% if ticket.is_older_than_day %}
{{ ticket.timestamp|date:"w M, Y" }} {{ ticket.timestamp|date:"D, w M Y" }}
{% else %} {% else %}
{{ ticket.timestamp|date:"H:i" }} {{ ticket.timestamp|date:"H:i" }}
{% endif %} {% endif %}
@ -225,7 +225,7 @@
</div> </div>
</div> </div>
<h5 class="fsz-def tt-c c-grey-900 ticket-title">{{ ticket.title }}</h5> <h5 class="fsz-def tt-c c-grey-900 ticket-title">{{ ticket.title }}</h5>
<span class="whs-nw w-100 ov-h tov-e d-b ticket-desc">{{ ticket.description }}</span> <span class="whs-nw w-100 ov-h tov-e d-b ticket-desc">{{ ticket.description|safe }}</span>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
@ -386,37 +386,68 @@
$('.email-content').toggleClass('open'); $('.email-content').toggleClass('open');
displayTicket(ticketElement); displayTicket(ticketElement);
}); });
$("#ticketTitle").text("")
$("#ticketDesc").empty();
$("#ticketAuthor").text("");
$("#ticketAuthorImg").hide();
$("#ticketAuthorImg").prop("src", "");
$("#ticketTimestamp").text("");
$("#btnGroupDrop2").hide();
$("#ticketBadges").hide();
if (displayedTicketID === ticketID) { if (displayedTicketID === ticketID) {
$("#ticketTitle").text("")
$("#ticketDesc").text("");
$("#ticketAuthor").text("");
$("#ticketAuthorImg").hide();
$("#ticketAuthorImg").prop("src", "");
$("#ticketTimestamp").text("");
$("#btnGroupDrop2").hide();
$("#ticketBadges").hide();
displayedTicketID = -1; displayedTicketID = -1;
return; return;
} }
displayedTicketID = ticketID; displayedTicketID = ticketID;
title = ticket.find(".ticket-title").text(); $.ajax({
desc = ticket.find(".ticket-desc").text(); url: `/tickets/get/${ticketID}`,
author = ticket.find(".ticket-author").text(); type: 'POST',
authorIcon = ticket.data("author-icon"); dataType: 'json',
timestamp = ticket.find(".ticket-timestamp").text(); data: {
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success: function (data) {
alert(JSON.stringify(data, null, 4));
$("#ticketTitle").text(title) var ticket = data.ticket;
$("#ticketDesc").text(desc); var author = ticket.author;
$("#ticketAuthor").text(author);
$("#ticketAuthorImg").show(); $("#ticketTitle").text(ticket.title);
$("#ticketAuthorImg").prop("src", authorIcon); $("#ticketDesc").append($(ticket.description));
$("#ticketTimestamp").text(timestamp); $("#ticketAuthor").text(author.name);
$("#btnGroupDrop2").show(); $("#ticketAuthorImg").show();
$("#ticketBadges").show(); $("#ticketAuthorImg").prop("src", author.icon);
$("#btnGroupDrop2").show();
$("#ticketBadges").show();
// timestamp
var timestamp = new Date(ticket.timestamp);
var formattedTime;
if (ticket.is_older_than_day) {
var options = { weekday: 'short', day: 'numeric', month: 'short', year: 'numeric' };
formattedTime = timestamp.toLocaleDateString('en-GB', options);
}
else {
var hours = timestamp.getUTCHours();
var minutes = timestamp.getUTCMinutes();
formattedTime = hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0');
}
if (ticket.is_edited) {
formattedTime += " • edited";
}
$("#ticketTimestamp").text(formattedTime);
},
error: function(message) {
alert(JSON.stringify(message, null, 4));
}
});
} }
</script> </script>
{% endblock javascripts %} {% endblock javascripts %}

View File

@ -1,5 +1,6 @@
asgiref==3.4.1 asgiref==3.4.1
autopep8==1.6.0 autopep8==1.6.0
bleach==6.1.0
dj-database-url==0.5.0 dj-database-url==0.5.0
Django==3.2.16 Django==3.2.16
django-environ==0.8.1 django-environ==0.8.1
@ -7,6 +8,8 @@ gunicorn==20.1.0
pillow==10.2.0 pillow==10.2.0
pycodestyle==2.8.0 pycodestyle==2.8.0
pytz==2021.3 pytz==2021.3
six==1.16.0
sqlparse==0.4.2 sqlparse==0.4.2
toml==0.10.2 toml==0.10.2
webencodings==0.5.1
whitenoise==5.3.0 whitenoise==5.3.0