from rest_framework import viewsets, permissions from .models import Project, Task from .serializers import ProjectSerializer, ProjectDetailSerializer, TaskSerializer, TaskDetailSerializer from accounts.permissions import IsAdmin, IsTeacher, IsStudentReadOnly from rest_framework.exceptions import PermissionDenied class ProjectViewSet(viewsets.ModelViewSet): """ CRUD for Projects. - list/retrieve: Admin, Teacher, Student - create/update/destroy: Admin, Teacher (but Teacher can only update/destroy their own) """ # Base permissions. Object-level is handled in check_object_permissions or via queryset permission_classes = [permissions.IsAuthenticated] def get_queryset(self): # Filter by tenant return Project.objects.tenant(self.request.tenant).select_related('created_by').order_by('-created_at') def get_serializer_class(self): if self.action in ['retrieve']: return ProjectDetailSerializer return ProjectSerializer def perform_create(self, serializer): # Auto-set the tenant and creator serializer.save(tenant=self.request.tenant, created_by=self.request.user) def check_permissions(self, request): super().check_permissions(request) if request.user.role == 'student' and request.method not in permissions.SAFE_METHODS: raise PermissionDenied("Students cannot modify projects.") def check_object_permissions(self, request, obj): super().check_object_permissions(request, obj) if request.method not in permissions.SAFE_METHODS: if request.user.role == 'teacher' and obj.created_by != request.user: raise PermissionDenied("You can only modify projects you created.") class TaskViewSet(viewsets.ModelViewSet): """ CRUD for Tasks nested under a Project. """ permission_classes = [permissions.IsAuthenticated] pagination_class = None # Return all tasks as list, not paginated def get_queryset(self): # The URL captures project_pk project_id = self.kwargs.get('project_pk') return Task.objects.tenant(self.request.tenant).filter(project_id=project_id).select_related('assigned_to', 'project').order_by('-created_at') def get_serializer_class(self): if self.action in ['retrieve', 'create', 'update', 'partial_update']: return TaskDetailSerializer return TaskSerializer def perform_create(self, serializer): project_id = self.kwargs.get('project_pk') try: project = Project.objects.get(id=project_id) except Project.DoesNotExist: raise serializers.ValidationError("Project does not exist.") # Check permissions before allowing to create task if self.request.user.role == 'teacher' and project.created_by != self.request.user: raise PermissionDenied("You can only add tasks to projects you created.") assigned_to_id = self.request.data.get('assigned_to_id') serializer.save(tenant=self.request.tenant, project=project, assigned_to_id=assigned_to_id) def perform_update(self, serializer): assigned_to_id = self.request.data.get('assigned_to_id') if 'assigned_to_id' in self.request.data: serializer.save(assigned_to_id=assigned_to_id) else: serializer.save() def check_permissions(self, request): super().check_permissions(request) if request.user.role == 'student' and request.method not in permissions.SAFE_METHODS: raise PermissionDenied("Students cannot modify tasks.") def check_object_permissions(self, request, obj): super().check_object_permissions(request, obj) if request.method not in permissions.SAFE_METHODS: if request.user.role == 'teacher' and obj.project.created_by != request.user: raise PermissionDenied("You can only modify tasks in projects you created.")