from functools import partial from typing import Type from django.core.exceptions import ValidationError from django.shortcuts import get_object_or_404 from rest_framework import generics, status from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from .permissions import CanEditLabel from .serializers import ( CategorySerializer, RelationSerializer, SpanSerializer, TextLabelSerializer, ) from labels.models import Category, Label, Relation, Span, TextLabel from projects.models import Project from projects.permissions import IsProjectMember class BaseListAPI(generics.ListCreateAPIView): label_class: Type[Label] pagination_class = None permission_classes = [IsAuthenticated & IsProjectMember] swagger_schema = None @property def project(self): return get_object_or_404(Project, pk=self.kwargs["project_id"]) def get_queryset(self): queryset = self.label_class.objects.filter(example=self.kwargs["example_id"]) if not self.project.collaborative_annotation: queryset = queryset.filter(user=self.request.user) return queryset def create(self, request, *args, **kwargs): request.data["example"] = self.kwargs["example_id"] try: response = super().create(request, args, kwargs) except ValidationError as err: response = Response({"detail": err.messages}, status=status.HTTP_400_BAD_REQUEST) return response def perform_create(self, serializer): serializer.save(example_id=self.kwargs["example_id"], user=self.request.user) def delete(self, request, *args, **kwargs): queryset = self.get_queryset() queryset.all().delete() return Response(status=status.HTTP_204_NO_CONTENT) class BaseDetailAPI(generics.RetrieveUpdateDestroyAPIView): lookup_url_kwarg = "annotation_id" swagger_schema = None @property def project(self): return get_object_or_404(Project, pk=self.kwargs["project_id"]) def get_permissions(self): if self.project.collaborative_annotation: self.permission_classes = [IsAuthenticated & IsProjectMember] else: self.permission_classes = [IsAuthenticated & IsProjectMember & partial(CanEditLabel, self.queryset)] return super().get_permissions() class CategoryListAPI(BaseListAPI): label_class = Category serializer_class = CategorySerializer def create(self, request, *args, **kwargs): if self.project.single_class_classification: self.get_queryset().delete() return super().create(request, args, kwargs) class CategoryDetailAPI(BaseDetailAPI): queryset = Category.objects.all() serializer_class = CategorySerializer class SpanListAPI(BaseListAPI): label_class = Span serializer_class = SpanSerializer class SpanDetailAPI(BaseDetailAPI): queryset = Span.objects.all() serializer_class = SpanSerializer class TextLabelListAPI(BaseListAPI): label_class = TextLabel serializer_class = TextLabelSerializer class TextLabelDetailAPI(BaseDetailAPI): queryset = TextLabel.objects.all() serializer_class = TextLabelSerializer class RelationList(generics.ListCreateAPIView): serializer_class = RelationSerializer pagination_class = None permission_classes = [IsAuthenticated & IsProjectMember] def get_queryset(self): project = get_object_or_404(Project, pk=self.kwargs["project_id"]) return project.annotation_relations def perform_create(self, serializer): project = get_object_or_404(Project, pk=self.kwargs["project_id"]) serializer.save(project=project) def delete(self, request, *args, **kwargs): delete_ids = request.data["ids"] Relation.objects.filter(pk__in=delete_ids).delete() return Response(status=status.HTTP_204_NO_CONTENT) class RelationDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Relation.objects.all() serializer_class = RelationSerializer lookup_url_kwarg = "annotation_id" permission_classes = [IsAuthenticated & IsProjectMember]