from django import forms from .models import Comment, Ticket from django.core.exceptions import ValidationError class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ["text"] widgets = { "text": forms.Textarea( attrs={"rows": 3, "placeholder": "Kommentar schreiben..."} ), } class TicketForm(forms.ModelForm): class Meta: model = Ticket fields = ["title", "description", "status", "priority", "course", "answer", "material"] widgets = { 'answer': forms.Textarea(attrs={ 'rows': 4, 'placeholder': 'Beschreibe die Lösung des Problems...' }) } 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 "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) # Automatische Tutor-Zuweisung basierend auf dem ausgewählten Kurs if ticket.course and ticket.course.tutor: ticket.assigned_to = ticket.course.tutor # 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