You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
8.4 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
5 years ago
6 years ago
6 years ago
6 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. from collections import Counter
  2. from django.shortcuts import get_object_or_404
  3. from django_filters.rest_framework import DjangoFilterBackend
  4. from django.db.models import Count
  5. from rest_framework import generics, filters, status
  6. from rest_framework.exceptions import ParseError, ValidationError
  7. from rest_framework.permissions import IsAuthenticated, IsAdminUser
  8. from rest_framework.response import Response
  9. from rest_framework.views import APIView
  10. from rest_framework.parsers import MultiPartParser
  11. from rest_framework_csv.renderers import CSVRenderer
  12. from .filters import DocumentFilter
  13. from .models import Project, Label, Document
  14. from .permissions import IsAdminUserAndWriteOnly, IsProjectUser, IsOwnAnnotation
  15. from .serializers import ProjectSerializer, LabelSerializer, DocumentSerializer, UserSerializer
  16. from .serializers import ProjectPolymorphicSerializer
  17. from .utils import CSVParser, JSONParser, PlainTextParser, CoNLLParser
  18. from .utils import JSONLRenderer
  19. from .utils import JSONPainter, CSVPainter
  20. class Me(APIView):
  21. permission_classes = (IsAuthenticated,)
  22. def get(self, request, *args, **kwargs):
  23. serializer = UserSerializer(request.user, context={'request': request})
  24. return Response(serializer.data)
  25. class ProjectList(generics.ListCreateAPIView):
  26. queryset = Project.objects.all()
  27. serializer_class = ProjectPolymorphicSerializer
  28. pagination_class = None
  29. permission_classes = (IsAuthenticated, IsAdminUserAndWriteOnly)
  30. def get_queryset(self):
  31. return self.request.user.projects
  32. def perform_create(self, serializer):
  33. serializer.save(users=[self.request.user])
  34. class ProjectDetail(generics.RetrieveUpdateDestroyAPIView):
  35. queryset = Project.objects.all()
  36. serializer_class = ProjectSerializer
  37. lookup_url_kwarg = 'project_id'
  38. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)
  39. class StatisticsAPI(APIView):
  40. pagination_class = None
  41. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)
  42. def get(self, request, *args, **kwargs):
  43. p = get_object_or_404(Project, pk=self.kwargs['project_id'])
  44. label_count, user_count = self.label_per_data(p)
  45. progress = self.progress(project=p)
  46. response = dict()
  47. response['label'] = label_count
  48. response['user'] = user_count
  49. response.update(progress)
  50. return Response(response)
  51. def progress(self, project):
  52. docs = project.documents
  53. annotation_class = project.get_annotation_class()
  54. total = docs.count()
  55. done = annotation_class.objects.filter(document_id__in=docs.all()).\
  56. aggregate(Count('document', distinct=True))['document__count']
  57. remaining = total - done
  58. return {'total': total, 'remaining': remaining}
  59. def label_per_data(self, project):
  60. label_count = Counter()
  61. user_count = Counter()
  62. annotation_class = project.get_annotation_class()
  63. docs = project.documents.all()
  64. annotations = annotation_class.objects.filter(document_id__in=docs.all())
  65. for d in annotations.values('label__text', 'user__username').annotate(Count('label'), Count('user')):
  66. label_count[d['label__text']] += d['label__count']
  67. user_count[d['user__username']] += d['user__count']
  68. return label_count, user_count
  69. class LabelList(generics.ListCreateAPIView):
  70. queryset = Label.objects.all()
  71. serializer_class = LabelSerializer
  72. pagination_class = None
  73. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)
  74. def get_queryset(self):
  75. queryset = self.queryset.filter(project=self.kwargs['project_id'])
  76. return queryset
  77. def perform_create(self, serializer):
  78. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  79. serializer.save(project=project)
  80. class LabelDetail(generics.RetrieveUpdateDestroyAPIView):
  81. queryset = Label.objects.all()
  82. serializer_class = LabelSerializer
  83. lookup_url_kwarg = 'label_id'
  84. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)
  85. class DocumentList(generics.ListCreateAPIView):
  86. queryset = Document.objects.all()
  87. serializer_class = DocumentSerializer
  88. filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
  89. search_fields = ('text', )
  90. ordering_fields = ('created_at', 'updated_at', 'doc_annotations__updated_at',
  91. 'seq_annotations__updated_at', 'seq2seq_annotations__updated_at')
  92. filter_class = DocumentFilter
  93. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)
  94. def get_queryset(self):
  95. queryset = self.queryset.filter(project=self.kwargs['project_id'])
  96. return queryset
  97. def perform_create(self, serializer):
  98. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  99. serializer.save(project=project)
  100. class DocumentDetail(generics.RetrieveUpdateDestroyAPIView):
  101. queryset = Document.objects.all()
  102. serializer_class = DocumentSerializer
  103. lookup_url_kwarg = 'doc_id'
  104. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)
  105. class AnnotationList(generics.ListCreateAPIView):
  106. pagination_class = None
  107. permission_classes = (IsAuthenticated, IsProjectUser)
  108. def get_serializer_class(self):
  109. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  110. self.serializer_class = project.get_annotation_serializer()
  111. return self.serializer_class
  112. def get_queryset(self):
  113. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  114. model = project.get_annotation_class()
  115. self.queryset = model.objects.filter(document=self.kwargs['doc_id'],
  116. user=self.request.user)
  117. return self.queryset
  118. def create(self, request, *args, **kwargs):
  119. request.data['document'] = self.kwargs['doc_id']
  120. return super().create(request, args, kwargs)
  121. def perform_create(self, serializer):
  122. doc = get_object_or_404(Document, pk=self.kwargs['doc_id'])
  123. serializer.save(document=doc, user=self.request.user)
  124. class AnnotationDetail(generics.RetrieveUpdateDestroyAPIView):
  125. lookup_url_kwarg = 'annotation_id'
  126. permission_classes = (IsAuthenticated, IsProjectUser, IsOwnAnnotation)
  127. def get_serializer_class(self):
  128. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  129. self.serializer_class = project.get_annotation_serializer()
  130. return self.serializer_class
  131. def get_queryset(self):
  132. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  133. model = project.get_annotation_class()
  134. self.queryset = model.objects.all()
  135. return self.queryset
  136. class TextUploadAPI(APIView):
  137. parser_classes = (MultiPartParser,)
  138. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUser)
  139. def post(self, request, *args, **kwargs):
  140. if 'file' not in request.data:
  141. raise ParseError('Empty content')
  142. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  143. parser = self.select_parser(request.data['format'])
  144. data = parser.parse(request.data['file'])
  145. storage = project.get_storage(data)
  146. storage.save(self.request.user)
  147. return Response(status=status.HTTP_201_CREATED)
  148. def select_parser(self, format):
  149. if format == 'plain':
  150. return PlainTextParser()
  151. elif format == 'csv':
  152. return CSVParser()
  153. elif format == 'json':
  154. return JSONParser()
  155. elif format == 'conll':
  156. return CoNLLParser()
  157. else:
  158. raise ValidationError('format {} is invalid.'.format(format))
  159. class TextDownloadAPI(APIView):
  160. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUser)
  161. renderer_classes = (CSVRenderer, JSONLRenderer)
  162. def get(self, request, *args, **kwargs):
  163. format = request.query_params.get('q')
  164. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  165. documents = project.documents.all()
  166. painter = self.select_painter(format)
  167. data = painter.paint(documents)
  168. return Response(data)
  169. def select_painter(self, format):
  170. if format == 'csv':
  171. return CSVPainter()
  172. elif format == 'json':
  173. return JSONPainter()
  174. else:
  175. raise ValidationError('format {} is invalid.'.format(format))