fix: black formatting
This commit is contained in:
@@ -17,45 +17,55 @@ class CommentForm(forms.ModelForm):
|
||||
class TicketForm(forms.ModelForm):
|
||||
# Zentrale Definition der Status-Übergänge
|
||||
STATUS_TRANSITIONS = {
|
||||
'tutor': {
|
||||
'new': ['in_progress'],
|
||||
'in_progress': ['resolved', 'new'],
|
||||
'resolved': ['closed'],
|
||||
'closed': [],
|
||||
"tutor": {
|
||||
"new": ["in_progress"],
|
||||
"in_progress": ["resolved", "new"],
|
||||
"resolved": ["closed"],
|
||||
"closed": [],
|
||||
},
|
||||
'creator': {
|
||||
'new': [],
|
||||
'in_progress': [],
|
||||
'resolved': ['closed', 'new'],
|
||||
'closed': [],
|
||||
"creator": {
|
||||
"new": [],
|
||||
"in_progress": [],
|
||||
"resolved": ["closed", "new"],
|
||||
"closed": [],
|
||||
},
|
||||
'superuser': {
|
||||
"superuser": {
|
||||
# Superuser können alle Übergänge machen
|
||||
'new': ['in_progress', 'resolved', 'closed'],
|
||||
'in_progress': ['new', 'resolved', 'closed'],
|
||||
'resolved': ['new', 'in_progress', 'closed'],
|
||||
'closed': ['new', 'in_progress', 'resolved'],
|
||||
}
|
||||
"new": ["in_progress", "resolved", "closed"],
|
||||
"in_progress": ["new", "resolved", "closed"],
|
||||
"resolved": ["new", "in_progress", "closed"],
|
||||
"closed": ["new", "in_progress", "resolved"],
|
||||
},
|
||||
}
|
||||
|
||||
# Zentrale Definition welche Felder wann required sind
|
||||
REQUIRED_FIELDS_BY_STATUS = {
|
||||
'resolved': ['answer'], # Answer required when resolving
|
||||
"resolved": ["answer"], # Answer required when resolving
|
||||
}
|
||||
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = ["title", "description", "status", "mistake", "course", "answer", "material"]
|
||||
fields = [
|
||||
"title",
|
||||
"description",
|
||||
"status",
|
||||
"mistake",
|
||||
"course",
|
||||
"answer",
|
||||
"material",
|
||||
]
|
||||
widgets = {
|
||||
'answer': forms.Textarea(attrs={
|
||||
'rows': 4,
|
||||
'placeholder': 'Beschreibe die Lösung des Problems...'
|
||||
})
|
||||
"answer": forms.Textarea(
|
||||
attrs={
|
||||
"rows": 4,
|
||||
"placeholder": "Beschreibe die Lösung des Problems...",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.user = kwargs.pop('user', None)
|
||||
self.ticket = kwargs.pop('ticket', None)
|
||||
self.user = kwargs.pop("user", None)
|
||||
self.ticket = kwargs.pop("ticket", None)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if self.ticket and self.user:
|
||||
@@ -79,17 +89,17 @@ class TicketForm(forms.ModelForm):
|
||||
if is_superuser:
|
||||
return
|
||||
|
||||
if self.ticket.status == 'resolved' and is_creator:
|
||||
if self.ticket.status == "resolved" and is_creator:
|
||||
for field_name in self.fields:
|
||||
if field_name == "answer":
|
||||
self.fields[field_name].disabled = True
|
||||
elif is_tutor:
|
||||
# Tutor darf ändern:
|
||||
readonly_fields = ['title', 'description', 'material']
|
||||
readonly_fields = ["title", "description", "material"]
|
||||
for field_name in readonly_fields:
|
||||
if field_name in self.fields:
|
||||
self.fields[field_name].disabled = True
|
||||
elif is_creator and self.ticket.status != 'resolved':
|
||||
elif is_creator and self.ticket.status != "resolved":
|
||||
for field_name in self.fields:
|
||||
self.fields[field_name].disabled = True
|
||||
|
||||
@@ -99,11 +109,11 @@ class TicketForm(forms.ModelForm):
|
||||
|
||||
# Superuser bekommen alle Status-Optionen
|
||||
if is_superuser:
|
||||
role = 'superuser'
|
||||
role = "superuser"
|
||||
elif is_tutor:
|
||||
role = 'tutor'
|
||||
role = "tutor"
|
||||
elif is_creator:
|
||||
role = 'creator'
|
||||
role = "creator"
|
||||
else:
|
||||
role = None
|
||||
|
||||
@@ -114,10 +124,9 @@ class TicketForm(forms.ModelForm):
|
||||
allowed_statuses = [current_status]
|
||||
|
||||
# Status-Choices filtern
|
||||
all_choices = list(self.fields['status'].choices)
|
||||
self.fields['status'].choices = [
|
||||
choice for choice in all_choices
|
||||
if choice[0] in allowed_statuses
|
||||
all_choices = list(self.fields["status"].choices)
|
||||
self.fields["status"].choices = [
|
||||
choice for choice in all_choices if choice[0] in allowed_statuses
|
||||
]
|
||||
|
||||
def _get_allowed_transitions(self, from_status, role):
|
||||
@@ -137,7 +146,7 @@ class TicketForm(forms.ModelForm):
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
status = cleaned_data.get('status')
|
||||
status = cleaned_data.get("status")
|
||||
|
||||
if not self.ticket or not status:
|
||||
return cleaned_data
|
||||
@@ -150,27 +159,31 @@ class TicketForm(forms.ModelForm):
|
||||
|
||||
# Superuser dürfen alle Übergänge
|
||||
if is_superuser:
|
||||
role = 'superuser'
|
||||
role = "superuser"
|
||||
elif is_tutor:
|
||||
role = 'tutor'
|
||||
role = "tutor"
|
||||
elif is_creator:
|
||||
role = 'creator'
|
||||
role = "creator"
|
||||
else:
|
||||
role = None
|
||||
|
||||
if role and not self._is_transition_allowed(old_status, status, role):
|
||||
raise ValidationError({
|
||||
'status': f'Übergang von "{self.ticket.get_status_display()}" zu "{dict(self.fields["status"].choices)[status]}" ist nicht erlaubt.'
|
||||
})
|
||||
raise ValidationError(
|
||||
{
|
||||
"status": f'Übergang von "{self.ticket.get_status_display()}" zu "{dict(self.fields["status"].choices)[status]}" ist nicht erlaubt.'
|
||||
}
|
||||
)
|
||||
|
||||
# Prüfe required fields für neuen Status
|
||||
required_fields = self._get_required_fields_for_status(status)
|
||||
for field_name in required_fields:
|
||||
if not cleaned_data.get(field_name):
|
||||
field_label = self.fields[field_name].label
|
||||
raise ValidationError({
|
||||
field_name: f'{field_label} ist erforderlich, wenn der Status auf "{dict(self.fields["status"].choices)[status]}" gesetzt wird.'
|
||||
})
|
||||
raise ValidationError(
|
||||
{
|
||||
field_name: f'{field_label} ist erforderlich, wenn der Status auf "{dict(self.fields["status"].choices)[status]}" gesetzt wird.'
|
||||
}
|
||||
)
|
||||
|
||||
return cleaned_data
|
||||
|
||||
@@ -184,8 +197,9 @@ class TicketForm(forms.ModelForm):
|
||||
# Setze answered_at wenn eine Antwort gegeben wird
|
||||
if ticket.answer and not ticket.answered_at:
|
||||
from django.utils import timezone
|
||||
|
||||
ticket.answered_at = timezone.now()
|
||||
|
||||
if commit:
|
||||
ticket.save()
|
||||
return ticket
|
||||
return ticket
|
||||
|
||||
@@ -4,8 +4,11 @@ from django.contrib.auth.models import User
|
||||
|
||||
class Course(models.Model):
|
||||
"""Kurs-Model für Backend-Verwaltung"""
|
||||
|
||||
name = models.CharField(max_length=200, verbose_name="Kurs-Name")
|
||||
code = models.CharField(max_length=50, unique=True, verbose_name="Kurs-Code") # z.B. "PROG-101"
|
||||
code = models.CharField(
|
||||
max_length=50, unique=True, verbose_name="Kurs-Code"
|
||||
) # z.B. "PROG-101"
|
||||
description = models.TextField(blank=True, verbose_name="Beschreibung")
|
||||
|
||||
tutor = models.ForeignKey(
|
||||
@@ -14,14 +17,14 @@ class Course(models.Model):
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name="Tutor",
|
||||
related_name="courses_as_tutor"
|
||||
related_name="courses_as_tutor",
|
||||
)
|
||||
|
||||
is_active = models.BooleanField(default=True, verbose_name="Aktiv")
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
ordering = ["name"]
|
||||
verbose_name = "Kurs"
|
||||
verbose_name_plural = "Kurse"
|
||||
|
||||
@@ -64,37 +67,40 @@ class Ticket(models.Model):
|
||||
description = models.TextField()
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="new")
|
||||
mistake = models.CharField(max_length=20, choices=MISTAKE_CHOICES, default="medium")
|
||||
material = models.CharField(max_length=20, choices=MATERIAL_CHOICES, default="script")
|
||||
material = models.CharField(
|
||||
max_length=20, choices=MATERIAL_CHOICES, default="script"
|
||||
)
|
||||
|
||||
answer = models.TextField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Antwort/Lösung",
|
||||
help_text="Beschreibung der Lösung (erforderlich bei Status 'Gelöst')"
|
||||
help_text="Beschreibung der Lösung (erforderlich bei Status 'Gelöst')",
|
||||
)
|
||||
answered_at = models.DateTimeField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Beantwortet am"
|
||||
blank=True, null=True, verbose_name="Beantwortet am"
|
||||
)
|
||||
|
||||
course = models.ForeignKey(
|
||||
Course,
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name="Kurs",
|
||||
related_name="tickets"
|
||||
Course, on_delete=models.CASCADE, verbose_name="Kurs", related_name="tickets"
|
||||
)
|
||||
created_by = models.ForeignKey(
|
||||
User, related_name="tickets_created", on_delete=models.CASCADE
|
||||
)
|
||||
assigned_to = models.ForeignKey(
|
||||
User, related_name="tickets_assigned", null=True, blank=True, on_delete=models.CASCADE,
|
||||
User,
|
||||
related_name="tickets_assigned",
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"[{self.get_mistake_display()}] {self.title} ({self.get_status_display()})"
|
||||
return (
|
||||
f"[{self.get_mistake_display()}] {self.title} ({self.get_status_display()})"
|
||||
)
|
||||
|
||||
|
||||
class Comment(models.Model):
|
||||
@@ -126,15 +132,16 @@ class TicketHistory(models.Model):
|
||||
|
||||
class FAQ(models.Model):
|
||||
"""Einfaches FAQ Model"""
|
||||
|
||||
question = models.CharField(max_length=300, verbose_name="Frage")
|
||||
answer = models.TextField(verbose_name="Antwort")
|
||||
order = models.IntegerField(default=0, verbose_name="Reihenfolge")
|
||||
is_active = models.BooleanField(default=True, verbose_name="Aktiv")
|
||||
|
||||
class Meta:
|
||||
ordering = ['order', 'question']
|
||||
ordering = ["order", "question"]
|
||||
verbose_name = "FAQ"
|
||||
verbose_name_plural = "FAQs"
|
||||
|
||||
def __str__(self):
|
||||
return self.question
|
||||
return self.question
|
||||
|
||||
@@ -8,7 +8,7 @@ from .views import (
|
||||
AssignedTicketListView,
|
||||
TicketDetailUpdateView,
|
||||
faq_list,
|
||||
faq_pdf_download
|
||||
faq_pdf_download,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
@@ -22,6 +22,6 @@ urlpatterns = [
|
||||
path("new/", TicketCreateView.as_view(), name="create"),
|
||||
path("<int:pk>/modify/", TicketUpdateView.as_view(), name="modify"),
|
||||
path("meine-tickets/", AssignedTicketListView.as_view(), name="assigned-tickets"),
|
||||
path('faq/', faq_list, name='faq-list'),
|
||||
path('faq/download/', faq_pdf_download, name='faq-pdf-download'),
|
||||
path("faq/", faq_list, name="faq-list"),
|
||||
path("faq/download/", faq_pdf_download, name="faq-pdf-download"),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user