Skip to content

Commit c39b2b2

Browse files
committed
Add basic Change History functionality
1 parent 28d622b commit c39b2b2

File tree

10 files changed

+204
-80
lines changed

10 files changed

+204
-80
lines changed

issue_tracker/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
'accounts',
4242
'tickets',
4343
'taggit',
44+
'simple_history',
4445
]
4546

4647
MIDDLEWARE = [
@@ -51,6 +52,7 @@
5152
'django.contrib.auth.middleware.AuthenticationMiddleware',
5253
'django.contrib.messages.middleware.MessageMiddleware',
5354
'django.middleware.clickjacking.XFrameOptionsMiddleware',
55+
'simple_history.middleware.HistoryRequestMiddleware',
5456
]
5557

5658
ROOT_URLCONF = 'issue_tracker.urls'

templates/base.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
<meta name="viewport" content="width=device-width, initial-scale=1.0">
88
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
99
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
10+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
11+
rel="stylesheet">
1012
{% block head %}
1113
{% endblock %}
1214
<title>{% block title %}{% endblock %}</title>

tickets/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from django.contrib import admin
22
from .models import Ticket, Comment
3+
from simple_history.admin import SimpleHistoryAdmin
34

45
# Register your models here.
5-
admin.site.register(Ticket)
6+
admin.site.register(Ticket, SimpleHistoryAdmin)
67
admin.site.register(Comment)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.11.24 on 2020-02-21 14:35
3+
from __future__ import unicode_literals
4+
5+
from django.conf import settings
6+
from django.db import migrations, models
7+
import django.db.models.deletion
8+
import simple_history.models
9+
10+
11+
class Migration(migrations.Migration):
12+
13+
dependencies = [
14+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
15+
('tickets', '0024_auto_20200220_1743'),
16+
]
17+
18+
operations = [
19+
migrations.CreateModel(
20+
name='ChangeHistory',
21+
fields=[
22+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
23+
('date', models.DateTimeField(auto_now_add=True)),
24+
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tickets.Ticket')),
25+
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
26+
],
27+
),
28+
migrations.CreateModel(
29+
name='HistoricalTicket',
30+
fields=[
31+
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
32+
('ticket_type', models.CharField(choices=[('Bug', 'Bug'), ('Feature', 'Feature')], max_length=10)),
33+
('summary', models.CharField(max_length=300)),
34+
('created_date', models.DateTimeField(blank=True, editable=False)),
35+
('status', models.CharField(default='New', max_length=50)),
36+
('priority', models.CharField(default='Medium', max_length=50)),
37+
('assigned_to', models.CharField(default='Unassigned', max_length=200)),
38+
('description', models.TextField()),
39+
('upvotes', models.IntegerField(default=0)),
40+
('history_id', models.AutoField(primary_key=True, serialize=False)),
41+
('history_date', models.DateTimeField()),
42+
('history_change_reason', models.CharField(max_length=100, null=True)),
43+
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
44+
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
45+
('submitted_by', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
46+
],
47+
options={
48+
'verbose_name': 'historical ticket',
49+
'ordering': ('-history_date', '-history_id'),
50+
'get_latest_by': 'history_date',
51+
},
52+
bases=(simple_history.models.HistoricalChanges, models.Model),
53+
),
54+
]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.11.24 on 2020-02-21 15:50
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('tickets', '0025_changehistory_historicalticket'),
12+
]
13+
14+
operations = [
15+
migrations.RemoveField(
16+
model_name='changehistory',
17+
name='ticket',
18+
),
19+
migrations.RemoveField(
20+
model_name='changehistory',
21+
name='user',
22+
),
23+
migrations.DeleteModel(
24+
name='ChangeHistory',
25+
),
26+
]

tickets/models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.contrib.auth.models import User
44
from datetime import datetime
55
from taggit.managers import TaggableManager
6+
from simple_history.models import HistoricalRecords
67

78
# Create your models here.
89

@@ -20,6 +21,7 @@ class Ticket(models.Model):
2021
description = models.TextField()
2122
tags = TaggableManager(blank=True)
2223
upvotes = models.IntegerField(default=0)
24+
history = HistoricalRecords()
2325

2426
def __str__(self):
2527
return self.summary
@@ -40,3 +42,10 @@ def __str__(self):
4042

4143
class Meta:
4244
verbose_name_plural = "Comments"
45+
46+
47+
# class ChangeHistory(models.Model):
48+
# ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
49+
# user = models.ForeignKey(User, on_delete=models.CASCADE)
50+
# date = models.DateTimeField(auto_now_add=True)
51+
# field?

tickets/templates/tickets.html

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,56 @@ <h2>Tickets</h2>
77
<hr>
88
{% endblock %}
99
{% block content %}
10-
<a class="btn btn-success" href="{% url 'add_ticket' %}">Raise Ticket</a>
11-
<input type="text" placeholder="Search"><button class="btn btn-info">Go</button></input>
12-
<br>
13-
<br>
14-
<table class="table table-sm">
15-
<thead>
16-
<tr>
17-
<th scope="col">ID</th>
18-
<th scope="col">Summary</th>
19-
<th scope="col">Type</th>
20-
<th scope="col">Submitted By</th>
21-
<th scope="col">Assigned To</th>
22-
<th scope="col">Status</th>
23-
<th scope="col">Priority</th>
24-
<th scope="col">Created</th>
25-
</tr>
26-
</thead>
27-
<tbody>
28-
{% for ticket in tickets %}
29-
<tr>
30-
<td scope="row">{{ ticket.id }}</td>
31-
<td><a href="{% url 'view_ticket' ticket.id %}">{{ ticket.summary }}</a></td>
32-
<td>{{ ticket.ticket_type }}</td>
33-
<td>{{ ticket.submitted_by }}</td>
34-
<td>{{ ticket.assigned_to }}</td>
35-
<td>{{ ticket.status }}</td>
36-
{% if ticket.priority == "Low" %}
37-
<td><span class="badge badge-pill badge-success">{{ ticket.priority }}</span></td>
38-
{% elif ticket.priority == "Medium" %}
39-
<td><span class="badge badge-pill badge-warning">{{ ticket.priority }}</span></td>
40-
{% elif ticket.priority == "High" %}
41-
<td><span class="badge badge-pill badge-danger">{{ ticket.priority }}</span></td>
42-
{% else %}
43-
<td><span class="badge badge-pill badge-light">{{ ticket.priority }}</span></td>
44-
{% endif %}
45-
<td>{{ ticket.created_date }}</td>
46-
</tr>
47-
{% endfor %}
48-
</tbody>
49-
</table>
10+
<div class="row">
11+
<div class="col col-2">
12+
<div class="checkbox">
13+
<label><input type="checkbox" value="bug">Bug</label>
14+
</div>
15+
<div class="checkbox">
16+
<label><input type="checkbox" value="feature">Feature</label>
17+
</div>
18+
</div>
19+
<div class="col col-10">
20+
<a class="btn btn-success" href="{% url 'add_ticket' %}">Raise Ticket</a>
21+
<input type="text" placeholder="Search"><button class="btn btn-info">Go</button></input>
22+
<br>
23+
<br>
24+
<table class="table table-sm">
25+
<thead>
26+
<tr>
27+
<th scope="col"><a href="?order=id">ID</th>
28+
<th scope="col"><a href="?order=summary">Summary</th>
29+
<th scope="col"><a href="?order=ticket_type">Type</a></th>
30+
<th scope="col"><a href="?order=submitted_by">Submitted By</th>
31+
<th scope="col"><a href="?order=assigned_to">Assigned To</th>
32+
<th scope="col"><a href="?order=status">Status</th>
33+
<th scope="col"><a href="?order=priority">Priority</th>
34+
<th scope="col"><a href="?order=created_date">Created</th>
35+
</tr>
36+
</thead>
37+
<tbody>
38+
{% for ticket in tickets %}
39+
<tr>
40+
<td scope="row">{{ ticket.id }}</td>
41+
<td><a href="{% url 'view_ticket' ticket.id %}">{{ ticket.summary }}</a></td>
42+
<td>{{ ticket.ticket_type }}</td>
43+
<td>{{ ticket.submitted_by }}</td>
44+
<td>{{ ticket.assigned_to }}</td>
45+
<td>{{ ticket.status }}</td>
46+
{% if ticket.priority == "Low" %}
47+
<td><span class="badge badge-pill badge-success">{{ ticket.priority }}</span></td>
48+
{% elif ticket.priority == "Medium" %}
49+
<td><span class="badge badge-pill badge-warning">{{ ticket.priority }}</span></td>
50+
{% elif ticket.priority == "High" %}
51+
<td><span class="badge badge-pill badge-danger">{{ ticket.priority }}</span></td>
52+
{% else %}
53+
<td><span class="badge badge-pill badge-light">{{ ticket.priority }}</span></td>
54+
{% endif %}
55+
<td>{{ ticket.created_date }}</td>
56+
</tr>
57+
{% endfor %}
58+
</tbody>
59+
</table>
60+
</div>
61+
</div>
5062
{% endblock %}

tickets/templates/view_ticket.html

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ <h2>View Ticket | {{ ticket.id}} </h2>
99
{% endblock %}
1010
{% block content %}
1111
<div class="row">
12-
<div class="col col-6">
12+
<div class="col col-5">
1313
<h4>Details</h4>
1414
<table class="table table-sm">
15-
<thead>
16-
<tr>
15+
{% comment %} <thead> {% endcomment %}
16+
{% comment %} <tr> {% endcomment %}
1717
{% comment %} <th scope="col">Field</th> {% endcomment %}
1818
{% comment %} <th scope="col">Value</th> {% endcomment %}
19-
</tr>
20-
</thead>
19+
{% comment %} </tr> {% endcomment %}
20+
{% comment %} </thead> {% endcomment %}
2121
<tbody>
2222
<tr>
2323
<th>Summary</th>
@@ -57,41 +57,56 @@ <h4>Details</h4>
5757
</tr>
5858
</tbody>
5959
</table>
60-
<a class="btn btn-outline-primary" href="{% url 'edit_ticket' ticket.id %}">Edit</a>
60+
<a class="btn btn-primary" href="{% url 'edit_ticket' ticket.id %}">Edit</a>
6161
{% if ticket.status != 'Cancelled' %}
62-
<a class="btn btn-outline-warning" href="{% url 'cancel_ticket' ticket.id %}">Cancel</a>
62+
<a class="btn btn-warning" href="{% url 'cancel_ticket' ticket.id %}">Cancel</a>
6363
{% endif %}
64-
<a class="btn btn-outline-danger" href="{% url 'delete_ticket' ticket.id %}">Delete</a>
64+
<a class="btn btn-danger" href="{% url 'delete_ticket' ticket.id %}">Delete</a>
6565
</div>
66-
<div class="col col-6">
66+
<div class="col col-7">
6767
<h4>Change History</h4>
6868
<table class="table table-sm">
6969
<thead>
7070
<tr>
71-
<th scope="col">Field</th>
71+
<th scope="col">Property</th>
7272
<th scope="col">New Value</th>
7373
<th scope="col">Old Value</th>
74-
<th scope="col">Date Changed</th>
74+
<th scope="col">User</th>
75+
<th scope="col">Date</th>
7576
</tr>
7677
</thead>
7778
<tbody>
79+
{% if all_deltas %}
80+
{% for delta in all_deltas %}
81+
<tr>
82+
<td>{{ delta.field }}</td>
83+
<td>{{ delta.new_value }}</td>
84+
<td>{{ delta.old_value }}</td>
85+
<td>{{ delta.changed_by }}</td>
86+
<td>{{ delta.date_changed }}</td>
87+
</tr>
88+
{% endfor %}
89+
{% else %}
7890
<tr>
79-
<td>Status</td>
80-
<td>High</td>
81-
<td>Medium</td>
82-
<td>20/02/2020</td>
91+
<td>-</td>
92+
<td>-</td>
93+
<td>-</td>
94+
<td>-</td>
95+
<td>-</td>
8396
</tr>
97+
{% endif %}
8498
</tbody>
8599
</table>
86100
</div>
87101
</div>
88102
<hr>
89103
<div class="row">
90-
<div class="col col-8">
104+
<div class="col col-12">
91105
<h4>Comments</h4>
92106
<ul class="list-group">
93107
{% for comment in comments %}
94-
<li class="list-group-item"><b>@{{ comment.user }}</b><span class="float-right">{{ comment.date }}</span>
108+
<li class="list-group-item"><b>@{{ comment.user }}</b><span class="float-right">
109+
<i>{{ comment.date }}</i></span>
95110
<br>{{ comment.comment_body }}
96111
</li>
97112
{% endfor %}

tickets/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
urlpatterns = [
55
url(r'^$', views.view_tickets, name='tickets'),
6+
# url(r'^(?P<sort_field>\w+)/$', views.view_tickets, name='tickets'),
67
url(r'^add_ticket/$', views.add_ticket, name='add_ticket'),
78
url(r'^(?P<pk>\d+)/$', views.view_ticket, name='view_ticket'),
89
url(r'^edit_ticket/(?P<pk>\d+)/$', views.edit_ticket, name='edit_ticket'),

0 commit comments

Comments
 (0)