default migrations

This commit is contained in:
Corban-Lee Jones 2024-01-05 12:06:50 +00:00
parent f630e00c21
commit a59baefd8f
23 changed files with 423 additions and 185 deletions

View File

@ -1,8 +1,8 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User from .models import User, Department
admin.site.register(User, UserAdmin) admin.site.register(User)
admin.site.register(Department)

View File

@ -5,14 +5,15 @@ Copyright (c) 2019 - present AppSeed.us
from django import forms from django import forms
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import User
class LoginForm(forms.Form): class LoginForm(forms.Form):
username = forms.CharField( email = forms.EmailField(
widget=forms.TextInput( widget=forms.EmailInput(
attrs={ attrs={
"placeholder": "Username", "placeholder": "Email Address",
"class": "form-control" "class": "form-control"
} }
)) ))
@ -26,10 +27,17 @@ class LoginForm(forms.Form):
class SignUpForm(UserCreationForm): class SignUpForm(UserCreationForm):
username = forms.CharField( forename = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
"placeholder": "Username", "placeholder": "Forename",
"class": "form-control"
}
))
surname = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "Surname",
"class": "form-control" "class": "form-control"
} }
)) ))
@ -50,11 +58,11 @@ class SignUpForm(UserCreationForm):
password2 = forms.CharField( password2 = forms.CharField(
widget=forms.PasswordInput( widget=forms.PasswordInput(
attrs={ attrs={
"placeholder": "Password check", "placeholder": "Password (Again)",
"class": "form-control" "class": "form-control"
} }
)) ))
class Meta: class Meta:
model = User model = User
fields = ('username', 'email', 'password1', 'password2') fields = ('forename', 'surname', 'email', 'password1', 'password2')

View File

@ -1,8 +1,7 @@
# Generated by Django 3.2.16 on 2024-01-04 14:05 # Generated by Django 3.2.16 on 2024-01-05 12:04
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone import django.utils.timezone
import uuid import uuid
@ -16,30 +15,36 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.CreateModel(
name='Department',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=150)),
('icon', models.CharField(blank=True, max_length=32, null=True)),
],
),
migrations.CreateModel( migrations.CreateModel(
name='User', name='User',
fields=[ fields=[
('password', models.CharField(max_length=128, verbose_name='password')), ('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('icon', models.ImageField(default='users/default.webp', upload_to='users', verbose_name='profile picture')),
('email', models.EmailField(error_messages={'unique': 'A user with this email address already exists.'}, max_length=254, unique=True, verbose_name='email address')),
('forename', models.CharField(help_text='This should be your real first name.', max_length=150, verbose_name='first name')),
('surname', models.CharField(help_text='This should be your real last name.', max_length=150, verbose_name='last name')),
('create_timestamp', models.DateTimeField(default=django.utils.timezone.now, help_text='When the user was created.', verbose_name='Creation Date')),
('edit_timestamp', models.DateTimeField(default=django.utils.timezone.now, help_text='When the user was last edited.', verbose_name='Last Edited')),
('is_active', models.BooleanField(default=True, help_text='Use as a "soft delete" rather than deleting the user.', verbose_name='active status')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_superuser', models.BooleanField(default=False, help_text='Designates whether the user has unrestricted site control.', verbose_name='superuser status')),
('department', models.ForeignKey(blank=True, help_text='Which department does this user belong to?', null=True, on_delete=django.db.models.deletion.SET_NULL, to='authentication.department', verbose_name='department')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
], ],
options={ options={
'verbose_name': 'user', 'verbose_name': 'user',
'verbose_name_plural': 'users', 'verbose_name_plural': 'users',
'abstract': False,
}, },
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
), ),
] ]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.16 on 2024-01-04 14:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='user',
name='icon',
field=models.ImageField(default='users/default.webp', upload_to='users'),
),
]

View File

@ -1,24 +0,0 @@
# Generated by Django 3.2.16 on 2024-01-04 14:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0002_user_icon'),
]
operations = [
migrations.AddField(
model_name='user',
name='name',
field=models.CharField(default='Corban-Lee Jones', max_length=150),
preserve_default=False,
),
migrations.AlterField(
model_name='user',
name='email',
field=models.EmailField(max_length=254, unique=True),
),
]

View File

@ -1,18 +0,0 @@
# 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

@ -0,0 +1,35 @@
# Generated by Django 3.2.16 on 2024-01-05 10:44
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
from django.apps import apps
import uuid
def create_departments(app, schema_editor):
Department = apps.get_model("authentication", "Department")
data = [
{"title": "Development", "icon": None},
{"title": "Sales", "icon": None},
{"title": "Marketing", "icon": None},
{"title": "Management", "icon": None},
{"title": "Business Strategy", "icon": None},
]
for item in data:
priority = Department.objects.create(title=item["title"], icon=item["icon"])
class Migration(migrations.Migration):
dependencies = [
("authentication", "0001_initial"),
]
operations = [
migrations.RunPython(create_departments)
]

View File

@ -3,23 +3,39 @@
import uuid import uuid
from django.db import models from django.db import models
from django.contrib.auth.models import AbstractUser, BaseUserManager from django.utils import timezone
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.utils.translation import gettext_lazy as _
class Department(models.Model):
title = models.CharField(max_length=150)
icon = models.CharField(max_length=32, null=True, blank=True)
def __str__(self):
return self.title
def serialize(self) -> dict:
return {
"title": self.title,
"icon": self.icon
}
class UserManager(BaseUserManager): class UserManager(BaseUserManager):
def create_user(self, email: str, name: str, password: str=None, **extra_fields): def create_user(self, email: str, forename: str, surname: str, password: str=None, **extra_fields):
if not email: if not email:
raise ValueError("Please provide an email address") raise ValueError("Please provide an email address")
email = self.normalize_email(email) email = self.normalize_email(email)
user = self.model(email=email, name=name, **extra_fields) user = self.model(email=email, forename=forename, surname=surname, **extra_fields)
user.set_password(password) user.set_password(password)
user.save() user.save()
return user return user
def create_superuser(self, email: str, name: str, password: str, **extra_fields): def create_superuser(self, email: str, forename: str, surname: str, password: str, **extra_fields):
extra_fields.setdefault("is_staff", True) extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True) extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("is_active", True) extra_fields.setdefault("is_active", True)
@ -30,27 +46,108 @@ class UserManager(BaseUserManager):
if not extra_fields.get("is_superuser"): if not extra_fields.get("is_superuser"):
raise ValueError("Superuser must have is_superuser=True") raise ValueError("Superuser must have is_superuser=True")
return self.create_user(email, name, password, **extra_fields) return self.create_user(email, forename, surname, password, **extra_fields)
class User(AbstractUser): class User(AbstractBaseUser, PermissionsMixin):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
icon = models.ImageField(upload_to="users", default="users/default.webp")
name = models.CharField(max_length=150) icon = models.ImageField(_("profile picture"), upload_to="users", default="users/default.webp")
email = models.EmailField(unique=True) email = models.EmailField(
_("email address"),
unique=True,
error_messages = {
"unique": _("A user with this email address already exists.")
}
)
forename = models.CharField(
_("first name"),
max_length=150,
help_text=_("This should be your real first name.")
)
surname = models.CharField(
_("last name"),
max_length=150,
help_text=_("This should be your real last name.")
)
department = models.ForeignKey(
Department,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name=_("department"),
help_text=_("Which department does this user belong to?")
)
create_timestamp = models.DateTimeField(
_("Creation Date"),
editable=True,
default=timezone.now,
help_text=_("When the user was created.")
)
edit_timestamp = models.DateTimeField(
_("Last Edited"),
editable=True,
default=timezone.now,
help_text=_("When the user was last edited.")
)
is_active = models.BooleanField(
_("active status"),
default=True,
help_text=_('Use as a "soft delete" rather than deleting the user.')
)
is_staff = models.BooleanField(
_("staff status"),
default=False,
help_text=_("Designates whether the user can log into this admin site.")
)
is_superuser = models.BooleanField(
_("superuser status"),
default=False,
help_text=_("Designates whether the user has unrestricted site control.")
)
USERNAME_FIELD = "email" USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["name"] EMAIL_FIELD = "email"
REQUIRED_FIELDS = ["forename", "surname"]
objects = UserManager() objects = UserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def __str__(self): def __str__(self):
return self.name return f"{self.id}{self.email}{self.formal_fullname}"
def save(self, *args, **kwargs):
self.edit_timestamp = timezone.now()
super().save(*args, **kwargs)
def clean(self):
super().clean()
self.email = self.__class__.objects.normalize_email(self.email)
@property
def fullname(self) -> str:
return f"{self.forename} {self.surname}"
@property
def formal_fullname(self) -> str:
return f"{self.surname}, {self.forename}"
def serialize(self) -> dict: def serialize(self) -> dict:
department = self.department.serialize() if self.department else None
return { return {
"id": self.id, "id": self.id,
"icon": self.icon.url, "icon": self.icon.url,
"name": self.name, "email": self.email,
"email": self.email "forename": self.forename,
"surname": self.surname,
"department": department,
"create_timestamp": self.create_timestamp,
"edit_timestamp": self.edit_timestamp
} }

View File

@ -15,9 +15,9 @@ def login_view(request):
if request.method == "POST": if request.method == "POST":
if form.is_valid(): if form.is_valid():
username = form.cleaned_data.get("username") email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password") password = form.cleaned_data.get("password")
user = authenticate(username=username, password=password) user = authenticate(username=email, password=password)
if user is not None: if user is not None:
login(request, user) login(request, user)
return redirect("/") return redirect("/")
@ -36,10 +36,16 @@ def register_user(request):
if request.method == "POST": if request.method == "POST":
form = SignUpForm(request.POST) form = SignUpForm(request.POST)
if form.is_valid(): if form.is_valid():
form.save() user = form.save(commit=False)
username = form.cleaned_data.get("username")
# Develepment, give all new users admin
user.is_staff = True
user.is_superuser = True
user.save()
email = form.cleaned_data.get("email")
raw_password = form.cleaned_data.get("password1") raw_password = form.cleaned_data.get("password1")
user = authenticate(username=username, password=raw_password) user = authenticate(username=email, password=raw_password)
msg = 'User created successfully.' msg = 'User created successfully.'
success = True success = True

View File

@ -2,6 +2,8 @@
from django.contrib import admin from django.contrib import admin
from .models import Ticket from .models import Ticket, TicketPriority, TicketTag
admin.site.register(Ticket) admin.site.register(Ticket)
admin.site.register(TicketPriority)
admin.site.register(TicketTag)

View File

@ -1,9 +1,10 @@
# Generated by Django 3.2.16 on 2024-01-04 14:05 # Generated by Django 3.2.16 on 2024-01-05 10:44
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import django.utils.timezone import django.utils.timezone
import uuid
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -34,12 +35,14 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='Ticket', name='Ticket',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('title', models.CharField(max_length=60)), ('title', models.CharField(help_text='An extremely short summary of the ticket subject.', max_length=100, verbose_name='title')),
('description', models.TextField(max_length=650)), ('description', models.TextField(help_text='Detailed description of the ticket subject.', max_length=650, verbose_name='description')),
('create_timestamp', models.DateTimeField(default=django.utils.timezone.now)), ('create_timestamp', models.DateTimeField(default=django.utils.timezone.now, help_text='When the user was created.', verbose_name='Creation Date')),
('edit_timestamp', models.DateTimeField(default=django.utils.timezone.now)), ('edit_timestamp', models.DateTimeField(default=django.utils.timezone.now, help_text='When the user was last edited.', verbose_name='Last Edited')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('author', models.ForeignKey(help_text='The creator of the ticket.', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author')),
('priority', models.ForeignKey(help_text='The importance level of this ticket.', on_delete=django.db.models.deletion.CASCADE, to='home.ticketpriority', verbose_name='priority')),
('tags', models.ManyToManyField(blank=True, help_text='Categories of the ticket.', to='home.TicketTag', verbose_name='tags')),
], ],
), ),
] ]

View File

@ -1,19 +0,0 @@
# 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

@ -0,0 +1,34 @@
# Generated by Django 3.2.16 on 2024-01-05 10:44
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
from django.apps import apps
import uuid
def create_priorities(app, schema_editor):
TicketPriority = apps.get_model("home", "TicketPriority")
data = [
{"title": "Urgent", "colour": "#FF0000"},
{"title": "High", "colour": "#FFA500"},
{"title": "Normal", "colour": "#FFFF00"},
{"title": "Low", "colour": "#008000"}
]
for item in data:
priority = TicketPriority.objects.create(title=item["title"], colour=item["colour"])
class Migration(migrations.Migration):
dependencies = [
("home", "0001_initial"),
]
operations = [
migrations.RunPython(create_priorities)
]

View File

@ -0,0 +1,36 @@
# Generated by Django 3.2.16 on 2024-01-05 10:44
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
from django.apps import apps
import uuid
def create_tags(app, schema_editor):
TicketTag = apps.get_model("home", "TicketTag")
data = [
{"title": "Network", "colour": "#0000FF"},
{"title": "Software", "colour": "#FFA500"},
{"title": "Hardware", "colour": "#808080"},
{"title": "Question", "colour": "#FFFF00"},
{"title": "Require's Help", "colour": "#00FF00"},
{"title": "Issue", "colour": "#FF0000"}
]
for item in data:
priority = TicketTag.objects.create(title=item["title"], colour=item["colour"])
class Migration(migrations.Migration):
dependencies = [
("home", "default_priorities"),
]
operations = [
migrations.RunPython(create_tags)
]

View File

@ -7,28 +7,86 @@ from datetime import timedelta, datetime
from django.db import models from django.db import models
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _
class TicketPriority(models.Model): class TicketPriority(models.Model):
title = models.CharField(max_length=32) title = models.CharField(max_length=32)
colour = models.CharField(max_length=7) colour = models.CharField(max_length=7)
def __str__(self):
return self.title
def serialize(self) -> dict:
return {
"title": self.title,
"colour": self.colour
}
class TicketTag(models.Model): class TicketTag(models.Model):
title = models.CharField(max_length=32) title = models.CharField(max_length=32)
colour = models.CharField(max_length=7) colour = models.CharField(max_length=7)
def __str__(self):
return self.title
def serialize(self) -> dict:
return {
"title": self.title,
"colour": self.colour
}
class Ticket(models.Model): class Ticket(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=60)
description = models.TextField(max_length=650) title = models.CharField(
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) _("title"),
create_timestamp = models.DateTimeField(editable=True, default=timezone.now) max_length=100,
edit_timestamp = models.DateTimeField(editable=True, default=timezone.now) help_text=_("An extremely short summary of the ticket subject.")
)
description = models.TextField(
_("description"),
max_length=650,
help_text=_("Detailed description of the ticket subject.")
)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("author"),
on_delete=models.CASCADE,
help_text=_("The creator of the ticket.")
)
priority = models.ForeignKey(
TicketPriority,
verbose_name=_("priority"),
on_delete=models.CASCADE,
help_text=_("The importance level of this ticket.")
)
tags = models.ManyToManyField(
TicketTag,
verbose_name=_("tags"),
blank=True,
help_text=_("Categories of the ticket.")
)
create_timestamp = models.DateTimeField(
_("Creation Date"),
editable=True,
default=timezone.now,
help_text=_("When the user was created.")
)
edit_timestamp = models.DateTimeField(
_("Last Edited"),
editable=True,
default=timezone.now,
help_text=_("When the user was last edited.")
)
def __str__(self): def __str__(self):
return f"#{self.id}{self.title}{self.author}" return f"#{self.id}{self.title}{f' {self.author.department.title}' if self.author.department else ''} {self.author.formal_fullname}"
def clean_description(self): def clean_description(self):
cleaned_description = bleach.clean( cleaned_description = bleach.clean(
@ -40,6 +98,7 @@ class Ticket(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.description = self.clean_description() self.description = self.clean_description()
self.edit_timestamp = timezone.now()
super().save(*args, **kwargs) super().save(*args, **kwargs)
@property @property
@ -91,5 +150,7 @@ class Ticket(models.Model):
"edit_timestamp": self.edit_timestamp, "edit_timestamp": self.edit_timestamp,
"is_edited": self.is_edited, "is_edited": self.is_edited,
"is_older_than_day": self.is_older_than_day, "is_older_than_day": self.is_older_than_day,
"timestamp": self.timestamp "timestamp": self.timestamp,
"priority": self.priority.serialize(),
"tags": [tag.serialize() for tag in self.tags.all()]
} }

View File

@ -11,7 +11,8 @@ from django.shortcuts import render
from django.urls import reverse from django.urls import reverse
from django.forms.models import model_to_dict from django.forms.models import model_to_dict
from .models import Ticket from ..authentication.models import Department
from .models import Ticket, TicketPriority, TicketTag
@login_required() @login_required()
@ -22,8 +23,15 @@ def dashboard(request):
@login_required() @login_required()
def tickets(request): def tickets(request):
tickets = Ticket.objects.all().order_by("-create_timestamp") tickets = Ticket.objects.all().order_by("-create_timestamp")
priorities = TicketPriority.objects.all()
tags = TicketTag.objects.all()
departments = Department.objects.all()
context = { context = {
"tickets": tickets, "tickets": tickets,
"priorities": priorities,
"tags": tags,
"departments": departments,
"dayago": datetime.now() - timedelta(hours=24) "dayago": datetime.now() - timedelta(hours=24)
} }

View File

@ -32,10 +32,10 @@
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label class="text-normal text-dark form-label">Username</label> <label class="text-normal text-dark form-label">Email Address</label>
{{ form.username }} {{ form.email }}
</div> </div>
<span class="text-error">{{ form.username.errors }}</span> <span class="text-error">{{ form.email.errors }}</span>
<div class="mb-3"> <div class="mb-3">
<label class="text-normal text-dark form-label">Password</label> <label class="text-normal text-dark form-label">Password</label>

View File

@ -40,10 +40,16 @@
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label class="form-label" class="text-normal text-dark">Username</label> <label class="form-label" class="text-normal text-dark">Forename</label>
{{ form.username }} {{ form.forename }}
</div> </div>
<span class="text-error">{{ form.username.errors }}</span> <span class="text-error">{{ form.forename.errors }}</span>
<div class="mb-3">
<label class="form-label" class="text-normal text-dark">Surname</label>
{{ form.surname }}
</div>
<span class="text-error">{{ form.surname.errors }}</span>
<div class="mb-3"> <div class="mb-3">
<label class="form-label" class="text-normal text-dark">Email Address</label> <label class="form-label" class="text-normal text-dark">Email Address</label>
@ -58,7 +64,7 @@
<span class="text-error">{{ form.password1.errors }}</span> <span class="text-error">{{ form.password1.errors }}</span>
<div class="mb-3"> <div class="mb-3">
<label class="form-label" class="text-normal text-dark">Password Check</label> <label class="form-label" class="text-normal text-dark">Password (Again)</label>
{{ form.password2 }} {{ form.password2 }}
</div> </div>
<span class="text-error">{{ form.password2.errors }}</span> <span class="text-error">{{ form.password2.errors }}</span>

View File

@ -22,39 +22,43 @@
<li class="nav-item"> <li class="nav-item">
<h6>Filters</h6> <h6>Filters</h6>
</li> </li>
<li class="nav-item ps-3 mT-15">
<h6 class="small">Priority</h6> {% if priorities %}
<div class="form-check"> <li class="nav-item ps-3 mT-15">
<input type="checkbox" id="priority1" class="form-check-input"> <h6 class="small">Priority</h6>
<label for="priority1" class="form-check-label">High</label> {% for priority in priorities %}
</div> <div class="form-check">
<div class="form-check"> <input type="checkbox" id="priority-{{ priority.id }}" class="form-check-input">
<input type="checkbox" id="priority2" class="form-check-input"> <label for="priority-{{ priority.id }}" class="form-check-label">{{ priority.title }}</label>
<label for="priority2" class="form-check-label">Medium</label> </div>
</div> {% endfor %}
<div class="form-check"> </li>
<input type="checkbox" id="priority3" class="form-check-input"> {% endif %}
<label for="priority3" class="form-check-label">Low</label>
</div> {% if departments %}
</li> <li class="nav-item ps-3 mT-15">
<li class="nav-item ps-3 mT-15"> <h6 class="small">Department</h6>
<h6 class="small">Department</h6> {% for department in departments %}
<div class="form-check"> <div class="form-check">
<input type="checkbox" id="sales" class="form-check-input"> <input type="checkbox" id="department-{{ department.id }}" class="form-check-input">
<label for="sales" class="form-check-label">Sales</label> <label for="department-{{ department.id }}" class="form-check-label">{{ department.title }}</label>
</div> </div>
<div class="form-check"> {% endfor %}
<input type="checkbox" id="strategy" class="form-check-input"> </li>
<label for="strategy" class="form-check-label">Strategy</label> {% endif %}
</div>
<div class="form-check"> {% if tags %}
<input type="checkbox" id="marketing" class="form-check-input"> <li class="nav-item ps-3 mT-15">
<label for="marketing" class="form-check-label">Marketing</label> <h6 class="small">Tags</h6>
</div> {% for tag in tags %}
</li> <div class="form-check">
<li class="nav-item ps-3 mT-15"> <input type="checkbox" id="tag-{{ tag.id }}" class="form-check-input">
<h6 class="small">Tags</h6> <label for="tag-{{ tag.id }}" class="form-check-label">{{ tag.title }}</label>
</li> </div>
{% endfor %}
</li>
{% endif %}
<!-- <li class="nav-item mt-5"> <!-- <li class="nav-item mt-5">
<a href="javascript:void(0)" class="nav-link c-grey-800 cH-blue-500 actived"> <a href="javascript:void(0)" class="nav-link c-grey-800 cH-blue-500 actived">
<div class="peers ai-c jc-sb"> <div class="peers ai-c jc-sb">
@ -209,7 +213,7 @@
<div class="peer peer-greed ov-h"> <div class="peer peer-greed ov-h">
<div class="peers ai-c"> <div class="peers ai-c">
<div class="peer peer-greed"> <div class="peer peer-greed">
<h6 class="ticket-author mb-0">{{ ticket.author }}</h6> <h6 class="ticket-author mb-0">{{ ticket.author.fullname }}</h6>
</div> </div>
<div class="peer"> <div class="peer">
<small class="ticket-timestamp"> <small class="ticket-timestamp">
@ -394,7 +398,7 @@
$("#ticketAuthorImg").prop("src", ""); $("#ticketAuthorImg").prop("src", "");
$("#ticketTimestamp").text(""); $("#ticketTimestamp").text("");
$("#btnGroupDrop2").hide(); $("#btnGroupDrop2").hide();
$("#ticketBadges").hide(); $("#ticketBadges").empty().hide();
if (displayedTicketID === ticketID) { if (displayedTicketID === ticketID) {
displayedTicketID = -1; displayedTicketID = -1;
@ -411,19 +415,31 @@
csrfmiddlewaretoken: '{{ csrf_token }}' csrfmiddlewaretoken: '{{ csrf_token }}'
}, },
success: function (data) { success: function (data) {
alert(JSON.stringify(data, null, 4)); console.log(JSON.stringify(data, null, 4));
var ticket = data.ticket; var ticket = data.ticket;
var author = ticket.author; var author = ticket.author;
var department = author.department;
var priority = ticket.priority;
$("#ticketTitle").text(ticket.title); $("#ticketTitle").text(ticket.title);
$("#ticketDesc").append($(ticket.description)); $("#ticketDesc").append($(`<div>${ticket.description}</div>`));
$("#ticketAuthor").text(author.name); $("#ticketAuthor").text(`${author.forename} ${author.surname}`);
$("#ticketAuthorImg").show(); $("#ticketAuthorImg").show();
$("#ticketAuthorImg").prop("src", author.icon); $("#ticketAuthorImg").prop("src", author.icon);
$("#btnGroupDrop2").show(); $("#btnGroupDrop2").show();
$("#ticketBadges").show(); $("#ticketBadges").show();
$("#ticketBadges").append($(`<div class="badge me-1" style="background-color: ${priority.colour};">${priority.title}</div>`));
if (department != null) {
$("#ticketBadges").append($(`<div class="badge bgc-deep-purple-500 me-1">${department.title}</div>`));
}
ticket.tags.forEach(function(tag) {
$("#ticketBadges").append($(`<div class="badge me-1" style="background-color: ${tag.colour};">${tag.title}</div>`));
});
// timestamp // timestamp
var timestamp = new Date(ticket.timestamp); var timestamp = new Date(ticket.timestamp);
var formattedTime; var formattedTime;

View File

@ -184,7 +184,7 @@
<img class="w-2r bdrs-50p" src="{{ request.user.icon.url }}" alt=""> <img class="w-2r bdrs-50p" src="{{ request.user.icon.url }}" alt="">
</div> </div>
<div class="peer"> <div class="peer">
<span class="fsz-sm c-grey-900">{{ request.user }}</span> <span class="fsz-sm c-grey-900">{{ request.user.formal_fullname }}</span>
</div> </div>
</a> </a>
<ul class="dropdown-menu fsz-sm"> <ul class="dropdown-menu fsz-sm">

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
media/users/download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB