From f5d2550000dd8ba7ebd4e601adc33017aace07bc Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 31 May 2025 21:32:55 +0200 Subject: [PATCH] feat: added permissions and allowed transitions logic --- ticketsystem/forms.py | 87 ++++++++++++++++++- .../templates/ticketsystem/detail.html | 12 +-- .../templates/ticketsystem/ticket_form.html | 4 +- ticketsystem/views.py | 31 +++++-- 4 files changed, 117 insertions(+), 17 deletions(-) diff --git a/ticketsystem/forms.py b/ticketsystem/forms.py index d4f43cd..0cc4a76 100644 --- a/ticketsystem/forms.py +++ b/ticketsystem/forms.py @@ -25,19 +25,104 @@ class TicketForm(forms.ModelForm): }) } + def __init__(self, *args, **kwargs): + # User und ticket aus kwargs holen (werden von der View übergeben) + self.user = kwargs.pop('user', None) + self.ticket = kwargs.pop('ticket', None) + super().__init__(*args, **kwargs) + + # Status-Choices basierend auf aktueller Situation einschränken + if self.ticket and self.user: + self._limit_status_choices() + self._set_field_permissions() + + def _set_field_permissions(self): + """Setzt welche Felder bearbeitet werden dürfen""" + is_creator = self.user == self.ticket.created_by + is_tutor = self.user == self.ticket.assigned_to + is_superuser = self.user.is_superuser + + if is_tutor and not is_superuser: + # Tutor darf nur Status und Answer ändern + readonly_fields = ['title', 'description', 'course', 'priority'] + for field_name in readonly_fields: + if field_name in self.fields: + self.fields[field_name].disabled = True + elif is_creator and not is_superuser: + # Ersteller darf gar nichts ändern + for field_name in self.fields: + self.fields[field_name].disabled = True + + def _limit_status_choices(self): + """Beschränkt die verfügbaren Status-Optionen basierend auf Rolle und aktuellem Status""" + current_status = self.ticket.status + is_creator = self.user == self.ticket.created_by + is_tutor = self.user == self.ticket.assigned_to + + # Alle möglichen Status + all_choices = list(self.fields['status'].choices) + allowed_choices = [] + + if is_tutor: + if current_status == 'new': + allowed_choices = ['new', 'in_progress'] + elif current_status == 'in_progress': + allowed_choices = ['in_progress', 'resolved', 'new'] + elif current_status == 'resolved': + allowed_choices = ['resolved', 'closed'] + elif current_status == 'closed': + allowed_choices = ['closed'] + else: + # Nicht-Tutoren sehen nur aktuellen Status + allowed_choices = [current_status] + + # Filtern der erlaubten Choices + self.fields['status'].choices = [ + choice for choice in all_choices + if choice[0] in allowed_choices + ] + def clean(self): cleaned_data = super().clean() status = cleaned_data.get('status') answer = cleaned_data.get('answer') - # Wenn Status auf "gelöst" gesetzt wird, muss eine Antwort vorhanden sein + # Wenn Status auf "resolved" gesetzt wird, muss eine Antwort vorhanden sein if status == 'resolved' and not answer: raise ValidationError({ 'answer': 'Eine Antwort ist erforderlich, wenn der Status auf "Gelöst" gesetzt wird.' }) + # Zusätzliche Validierung: Status-Übergang erlaubt? + if self.ticket and status: + old_status = self.ticket.status + if not self._is_status_transition_allowed(old_status, status): + raise ValidationError({ + 'status': f'Übergang von "{self.ticket.get_status_display()}" zu "{dict(self.fields["status"].choices)[status]}" ist nicht erlaubt.' + }) + return cleaned_data + def _is_status_transition_allowed(self, old_status, new_status): + """Prüft ob ein Status-Übergang erlaubt ist""" + if old_status == new_status: + return True + + is_tutor = self.user == self.ticket.assigned_to + + # Erlaubte Übergänge für Tutoren + allowed_transitions = { + 'new': ['in_progress'], + 'in_progress': ['resolved', 'new'], + 'resolved': ['closed'], + 'closed': [] # Keine Änderung von closed + } + + if is_tutor and old_status in allowed_transitions: + return new_status in allowed_transitions[old_status] + + return False + def save(self, commit=True): ticket = super().save(commit=False) diff --git a/ticketsystem/templates/ticketsystem/detail.html b/ticketsystem/templates/ticketsystem/detail.html index 1ce768c..168c867 100644 --- a/ticketsystem/templates/ticketsystem/detail.html +++ b/ticketsystem/templates/ticketsystem/detail.html @@ -25,15 +25,15 @@ + {% if not view.can_edit or form.title.field.disabled %}disabled{% endif %} + class="w-full p-2 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 {% if not view.can_edit or form.title.field.disabled %}bg-gray-100{% endif %}">
+ {% if not view.can_edit or form.description.field.disabled %}disabled{% endif %} + class="w-full p-2 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 {% if not view.can_edit or form.description.field.disabled %}bg-gray-100{% endif %}">{{ ticket.description }}
@@ -74,7 +74,7 @@
-
+
{% if ticket.assigned_to %}{{ ticket.assigned_to.username }}{% else %}Niemand zugewiesen{% endif %}

Wird automatisch basierend auf dem ausgewählten Kurs zugewiesen

@@ -104,7 +104,7 @@ rows="4" {% if not view.can_edit or ticket.status != 'resolved' %}disabled{% endif %} placeholder="Beschreibe die Lösung des Problems..." - class="w-full p-2 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-black {% if not view.can_edit or ticket.status != 'resolved' %}bg-gray-300 cursor-not-allowed{% endif %}">{{ ticket.answer|default:'' }} + class="w-full p-2 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-black {% if not view.can_edit or ticket.status != 'resolved' %}bg-gray-100 cursor-not-allowed{% endif %}">{{ ticket.answer|default:'' }} {% if form.answer.errors %}
{{ form.answer.errors }}
{% endif %} diff --git a/ticketsystem/templates/ticketsystem/ticket_form.html b/ticketsystem/templates/ticketsystem/ticket_form.html index adff900..9808921 100644 --- a/ticketsystem/templates/ticketsystem/ticket_form.html +++ b/ticketsystem/templates/ticketsystem/ticket_form.html @@ -64,7 +64,7 @@