feat: added ticket history
This commit is contained in:
@@ -36,3 +36,16 @@ class Comment(models.Model):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Kommentar von {self.author} zu Ticket #{self.ticket.id}"
|
return f"Kommentar von {self.author} zu Ticket #{self.ticket.id}"
|
||||||
|
|
||||||
|
|
||||||
|
class TicketHistory(models.Model):
|
||||||
|
ticket = models.ForeignKey("Ticket", on_delete=models.CASCADE, related_name="history")
|
||||||
|
changed_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
|
||||||
|
changed_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
field = models.CharField(max_length=100) # z. B. "status" oder "description"
|
||||||
|
old_value = models.TextField(null=True, blank=True)
|
||||||
|
new_value = models.TextField(null=True, blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ["-changed_at"]
|
||||||
|
|||||||
@@ -132,5 +132,22 @@
|
|||||||
<button type="submit">Absenden</button>
|
<button type="submit">Absenden</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<div style="margin-top: 3rem;">
|
||||||
|
<h2>🕓 Bearbeitungshistorie</h2>
|
||||||
|
{% if ticket.history.exists %}
|
||||||
|
<ul style="list-style: none; padding: 0;">
|
||||||
|
{% for entry in ticket.history.all %}
|
||||||
|
<li style="margin-bottom: 1rem; background-color: #f9f9f9; border-left: 4px solid #ccc; padding: 0.5rem 1rem;">
|
||||||
|
<strong>{{ entry.changed_by.username }}</strong>
|
||||||
|
hat <code>{{ entry.field }}</code> geändert:<br>
|
||||||
|
<em>{{ entry.old_value }}</em> → <strong>{{ entry.new_value }}</strong><br>
|
||||||
|
<small>am {{ entry.changed_at|date:"d.m.Y H:i" }}</small>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p><em>Keine Änderungen bisher.</em></p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -10,7 +10,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
|
||||||
from .models import Ticket
|
from .models import Ticket, TicketHistory
|
||||||
|
|
||||||
|
|
||||||
class HomeView(TemplateView):
|
class HomeView(TemplateView):
|
||||||
@@ -63,6 +63,7 @@ class TicketDetailView(FormMixin, DetailView):
|
|||||||
context["form"] = self.get_form()
|
context["form"] = self.get_form()
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class TicketCreateView(CreateView):
|
class TicketCreateView(CreateView):
|
||||||
model = Ticket
|
model = Ticket
|
||||||
fields = ["title", "description", "priority", "assigned_to"] # user & status wird automatisch gesetzt
|
fields = ["title", "description", "priority", "assigned_to"] # user & status wird automatisch gesetzt
|
||||||
@@ -74,6 +75,7 @@ class TicketCreateView(CreateView):
|
|||||||
form.instance.status = "open" # Neues Ticket beginnt immer als "offen"
|
form.instance.status = "open" # Neues Ticket beginnt immer als "offen"
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class TicketUpdateView(LoginRequiredMixin, UpdateView):
|
class TicketUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
model = Ticket
|
model = Ticket
|
||||||
fields = ["title", "description", "status", "priority", "assigned_to"]
|
fields = ["title", "description", "status", "priority", "assigned_to"]
|
||||||
@@ -90,3 +92,24 @@ class TicketUpdateView(LoginRequiredMixin, UpdateView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Ticket.objects.all() # Optional: Nur eigene Tickets bearbeiten lassen?
|
return Ticket.objects.all() # Optional: Nur eigene Tickets bearbeiten lassen?
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
ticket = form.instance
|
||||||
|
original = Ticket.objects.get(pk=ticket.pk)
|
||||||
|
|
||||||
|
response = super().form_valid(form) # Speichert das Ticket
|
||||||
|
|
||||||
|
tracked_fields = ["status", "description"]
|
||||||
|
for field in tracked_fields:
|
||||||
|
if field in form.changed_data:
|
||||||
|
old_value = getattr(original, field)
|
||||||
|
new_value = form.cleaned_data.get(field)
|
||||||
|
TicketHistory.objects.create(
|
||||||
|
ticket=ticket,
|
||||||
|
changed_by=self.request.user,
|
||||||
|
field=field,
|
||||||
|
old_value=str(old_value),
|
||||||
|
new_value=str(new_value),
|
||||||
|
)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|||||||
Reference in New Issue
Block a user