feat: added allowed transitions based on role

This commit is contained in:
2025-06-02 22:53:11 +02:00
parent 5205f4051c
commit 985b8cc88c
2 changed files with 46 additions and 20 deletions

View File

@@ -17,10 +17,18 @@ class CommentForm(forms.ModelForm):
class TicketForm(forms.ModelForm): class TicketForm(forms.ModelForm):
# Zentrale Definition der Status-Übergänge # Zentrale Definition der Status-Übergänge
STATUS_TRANSITIONS = { STATUS_TRANSITIONS = {
'new': ['in_progress'], 'tutor': {
'in_progress': ['resolved', 'closed'], 'new': ['in_progress'],
'resolved': ['closed'], 'in_progress': ['resolved', 'new'],
'closed': [], # Keine weiteren Übergänge 'resolved': ['closed'],
'closed': [],
},
'creator': {
'new': [],
'in_progress': [],
'resolved': ['closed', 'new'],
'closed': [],
}
} }
# Zentrale Definition welche Felder wann required sind # Zentrale Definition welche Felder wann required sind
@@ -61,13 +69,13 @@ class TicketForm(forms.ModelForm):
def _set_field_permissions(self, is_tutor, is_creator, is_superuser): def _set_field_permissions(self, is_tutor, is_creator, is_superuser):
"""Setzt welche Felder bearbeitet werden dürfen""" """Setzt welche Felder bearbeitet werden dürfen"""
if is_tutor and not is_superuser: if is_tutor and not is_superuser:
# Tutor darf nur Status und Answer ändern # Tutor darf ändern:
readonly_fields = ['title', 'description'] readonly_fields = ['title', 'description', 'material']
for field_name in readonly_fields: for field_name in readonly_fields:
if field_name in self.fields: if field_name in self.fields:
self.fields[field_name].disabled = True self.fields[field_name].disabled = True
elif is_creator and not is_superuser: elif is_creator and not is_superuser and self.ticket.status != 'resolved':
# Ersteller darf gar nichts ändern # Creator darf ändern bei resolved
for field_name in self.fields: for field_name in self.fields:
self.fields[field_name].disabled = True self.fields[field_name].disabled = True
@@ -76,9 +84,16 @@ class TicketForm(forms.ModelForm):
current_status = self.ticket.status current_status = self.ticket.status
if is_tutor: if is_tutor:
allowed_statuses = self._get_allowed_transitions(current_status) role = 'tutor'
elif is_creator:
role = 'creator'
else: else:
# Nicht-Tutoren sehen nur aktuellen Status role = None
if role:
allowed_statuses = self._get_allowed_transitions(current_status, role)
else:
# Andere User sehen nur aktuellen Status
allowed_statuses = [current_status] allowed_statuses = [current_status]
# Status-Choices filtern # Status-Choices filtern
@@ -88,18 +103,19 @@ class TicketForm(forms.ModelForm):
if choice[0] in allowed_statuses if choice[0] in allowed_statuses
] ]
def _get_allowed_transitions(self, from_status): def _get_allowed_transitions(self, from_status, role):
"""Gibt erlaubte Status-Übergänge zurück""" """Gibt erlaubte Status-Übergänge zurück (zentrale Logik)"""
return [from_status] + self.STATUS_TRANSITIONS.get(from_status, []) transitions = self.STATUS_TRANSITIONS.get(role, {}).get(from_status, [])
return [from_status] + transitions
def _is_transition_allowed(self, from_status, to_status): def _is_transition_allowed(self, from_status, to_status, role):
"""Prüft ob ein Status-Übergang erlaubt ist""" """Prüft ob ein Status-Übergang erlaubt ist"""
if from_status == to_status: if from_status == to_status:
return True return True
return to_status in self.STATUS_TRANSITIONS.get(from_status, []) return to_status in self.STATUS_TRANSITIONS.get(role, {}).get(from_status, [])
def _get_required_fields_for_status(self, status): def _get_required_fields_for_status(self, status):
"""Gibt zurück welche Felder für einen Status required sind""" """Gibt zurück, welche Felder für einen Status required sind"""
return self.REQUIRED_FIELDS_BY_STATUS.get(status, []) return self.REQUIRED_FIELDS_BY_STATUS.get(status, [])
def clean(self): def clean(self):
@@ -112,8 +128,16 @@ class TicketForm(forms.ModelForm):
# Prüfe Status-Übergang # Prüfe Status-Übergang
old_status = self.ticket.status old_status = self.ticket.status
is_tutor = self.user == self.ticket.assigned_to is_tutor = self.user == self.ticket.assigned_to
is_creator = self.user == self.ticket.created_by
if is_tutor and not self._is_transition_allowed(old_status, status): if is_tutor:
role = 'tutor'
elif is_creator:
role = 'creator'
else:
role = None
if role and not self._is_transition_allowed(old_status, status, role):
raise ValidationError({ raise ValidationError({
'status': f'Übergang von "{self.ticket.get_status_display()}" zu "{dict(self.fields["status"].choices)[status]}" ist nicht erlaubt.' 'status': f'Übergang von "{self.ticket.get_status_display()}" zu "{dict(self.fields["status"].choices)[status]}" ist nicht erlaubt.'
}) })

View File

@@ -85,8 +85,10 @@ class TicketDetailUpdateView(UpdateView):
is_assigned_tutor = user == self.ticket.assigned_to is_assigned_tutor = user == self.ticket.assigned_to
is_superuser = user.is_superuser is_superuser = user.is_superuser
# Nur Autor und Admin kann Tickets bearbeiten # Bearbeitungsrechte abhängig vom Status
if self.ticket.status == "closed" and not is_superuser: if self.ticket.status == 'resolved' and is_creator:
self.can_edit = True
elif self.ticket.status == 'closed' and not is_superuser:
self.can_edit = False self.can_edit = False
else: else:
self.can_edit = is_assigned_tutor or is_superuser self.can_edit = is_assigned_tutor or is_superuser