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.

258 lines
9.1 KiB

6 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
6 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
6 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
6 years ago
6 years ago
6 years ago
6 years ago
  1. import json
  2. from django_filters.rest_framework import DjangoFilterBackend
  3. from django.http import JsonResponse, HttpResponse
  4. from django.shortcuts import render, get_object_or_404
  5. from django.views import View
  6. from django.views.generic import TemplateView
  7. from django.views.generic.list import ListView
  8. from django.views.generic.detail import DetailView
  9. from django.contrib.auth.mixins import LoginRequiredMixin
  10. from rest_framework import viewsets, filters, generics
  11. from rest_framework.decorators import action
  12. from rest_framework.response import Response
  13. from rest_framework.permissions import SAFE_METHODS, BasePermission, IsAdminUser, IsAuthenticated
  14. from .models import Label, Document, Project, Factory
  15. from .models import DocumentAnnotation, SequenceAnnotation, Seq2seqAnnotation
  16. from .serializers import LabelSerializer, ProjectSerializer
  17. class IndexView(TemplateView):
  18. template_name = 'index.html'
  19. class ProjectView(LoginRequiredMixin, TemplateView):
  20. template_name = 'annotation.html'
  21. def get_context_data(self, **kwargs):
  22. context = super().get_context_data(**kwargs)
  23. project_id = kwargs.get('project_id')
  24. project = get_object_or_404(Project, pk=project_id)
  25. self.template_name = Factory.get_template(project)
  26. return context
  27. class ProjectAdminView(LoginRequiredMixin, DetailView):
  28. model = Project
  29. template_name = 'project_admin.html'
  30. class ProjectsView(LoginRequiredMixin, ListView):
  31. model = Project
  32. paginate_by = 100
  33. template_name = 'projects.html'
  34. class RawDataAPI(View):
  35. def post(self, request, *args, **kwargs):
  36. """Upload data."""
  37. f = request.FILES['file']
  38. content = ''.join(chunk.decode('utf-8') for chunk in f.chunks())
  39. for line in content.split('\n'):
  40. j = json.loads(line)
  41. Document(text=j['text']).save()
  42. return JsonResponse({'status': 'ok'})
  43. class DataDownloadAPI(View):
  44. def get(self, request, *args, **kwargs):
  45. annotated_docs = [a.as_dict() for a in Annotation.objects.filter(manual=True)]
  46. json_str = json.dumps(annotated_docs)
  47. response = HttpResponse(json_str, content_type='application/json')
  48. response['Content-Disposition'] = 'attachment; filename=annotation_data.json'
  49. return response
  50. class IsProjectUser(BasePermission):
  51. def has_permission(self, request, view):
  52. user = request.user
  53. project_id = view.kwargs.get('project_id')
  54. project = get_object_or_404(Project, pk=project_id)
  55. return user in project.users.all()
  56. class IsAdminUserAndWriteOnly(BasePermission):
  57. def has_permission(self, request, view):
  58. if request.method in SAFE_METHODS:
  59. return True
  60. return IsAdminUser().has_permission(request, view)
  61. class IsOwnAnnotation(BasePermission):
  62. def has_permission(self, request, view):
  63. user = request.user
  64. project_id = view.kwargs.get('project_id')
  65. annotation_id = view.kwargs.get('annotation_id')
  66. project = get_object_or_404(Project, pk=project_id)
  67. Annotation = Factory.get_annotation_class(project)
  68. annotation = Annotation.objects.get(id=annotation_id)
  69. return annotation.user == user
  70. class ProjectViewSet(viewsets.ModelViewSet):
  71. queryset = Project.objects.all()
  72. serializer_class = ProjectSerializer
  73. pagination_class = None
  74. permission_classes = (IsAuthenticated, IsAdminUserAndWriteOnly)
  75. @action(methods=['get'], detail=True)
  76. def progress(self, request, pk=None):
  77. project = self.get_object()
  78. docs = Factory.get_documents(project, is_null=True)
  79. total = project.documents.count()
  80. remaining = docs.count()
  81. return Response({'total': total, 'remaining': remaining})
  82. class ProjectLabelsAPI(generics.ListCreateAPIView):
  83. queryset = Label.objects.all()
  84. serializer_class = LabelSerializer
  85. pagination_class = None
  86. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)
  87. def get_queryset(self):
  88. project_id = self.kwargs['project_id']
  89. queryset = self.queryset.filter(project=project_id)
  90. return queryset
  91. def perform_create(self, serializer):
  92. project_id = self.kwargs['project_id']
  93. project = get_object_or_404(Project, pk=project_id)
  94. serializer.save(project=project)
  95. class ProjectLabelAPI(generics.RetrieveUpdateDestroyAPIView):
  96. queryset = Label.objects.all()
  97. serializer_class = LabelSerializer
  98. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUser)
  99. def get_queryset(self):
  100. project_id = self.kwargs['project_id']
  101. queryset = self.queryset.filter(project=project_id)
  102. return queryset
  103. def get_object(self):
  104. label_id = self.kwargs['label_id']
  105. queryset = self.filter_queryset(self.get_queryset())
  106. obj = get_object_or_404(queryset, pk=label_id)
  107. self.check_object_permissions(self.request, obj)
  108. return obj
  109. class ProjectDocsAPI(generics.ListCreateAPIView):
  110. queryset = Document.objects.all()
  111. filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
  112. search_fields = ('text', )
  113. permission_classes = (IsAuthenticated, IsProjectUser, IsAdminUserAndWriteOnly)
  114. def get_serializer_class(self):
  115. project_id = self.kwargs['project_id']
  116. project = get_object_or_404(Project, pk=project_id)
  117. self.serializer_class = Factory.get_project_serializer(project)
  118. return self.serializer_class
  119. def get_queryset(self):
  120. project_id = self.kwargs['project_id']
  121. queryset = self.queryset.filter(project=project_id)
  122. if not self.request.query_params.get('is_checked'):
  123. return queryset
  124. project = get_object_or_404(Project, pk=project_id)
  125. is_null = self.request.query_params.get('is_checked') == 'true'
  126. queryset = Factory.get_documents(project, is_null).distinct()
  127. return queryset
  128. class AnnotationsAPI(generics.ListCreateAPIView):
  129. pagination_class = None
  130. permission_classes = (IsAuthenticated, IsProjectUser)
  131. def get_serializer_class(self):
  132. project_id = self.kwargs['project_id']
  133. project = get_object_or_404(Project, pk=project_id)
  134. self.serializer_class = Factory.get_annotation_serializer(project)
  135. return self.serializer_class
  136. def get_queryset(self):
  137. doc_id = self.kwargs['doc_id']
  138. document = get_object_or_404(Document, pk=doc_id)
  139. self.queryset = Factory.get_annotations_by_doc(document)
  140. return self.queryset
  141. def post(self, request, *args, **kwargs):
  142. doc = get_object_or_404(Document, pk=self.kwargs['doc_id'])
  143. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  144. self.serializer_class = Factory.get_annotation_serializer(project)
  145. if project.is_type_of(Project.DOCUMENT_CLASSIFICATION):
  146. label = get_object_or_404(Label, pk=request.data['label_id'])
  147. annotation = DocumentAnnotation(document=doc, label=label, manual=True,
  148. user=self.request.user)
  149. elif project.is_type_of(Project.SEQUENCE_LABELING):
  150. label = get_object_or_404(Label, pk=request.data['label_id'])
  151. annotation = SequenceAnnotation(document=doc, label=label, manual=True,
  152. user=self.request.user,
  153. start_offset=request.data['start_offset'],
  154. end_offset=request.data['end_offset'])
  155. elif project.is_type_of(Project.Seq2seq):
  156. text = request.data['text']
  157. annotation = Seq2seqAnnotation(document=doc,
  158. text=text,
  159. manual=True,
  160. user=self.request.user)
  161. annotation.save()
  162. serializer = self.serializer_class(annotation)
  163. return Response(serializer.data)
  164. class AnnotationAPI(generics.RetrieveUpdateDestroyAPIView):
  165. permission_classes = (IsAuthenticated, IsProjectUser, IsOwnAnnotation)
  166. def get_queryset(self):
  167. doc_id = self.kwargs['doc_id']
  168. document = get_object_or_404(Document, pk=doc_id)
  169. self.queryset = Factory.get_annotations_by_doc(document)
  170. return self.queryset
  171. def get_object(self):
  172. annotation_id = self.kwargs['annotation_id']
  173. queryset = self.filter_queryset(self.get_queryset())
  174. obj = get_object_or_404(queryset, pk=annotation_id)
  175. self.check_object_permissions(self.request, obj)
  176. return obj
  177. def put(self, request, *args, **kwargs):
  178. doc = get_object_or_404(Document, pk=self.kwargs['doc_id'])
  179. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  180. self.serializer_class = Factory.get_annotation_serializer(project)
  181. if project.is_type_of(Project.Seq2seq):
  182. text = request.data['text']
  183. annotation = get_object_or_404(Seq2seqAnnotation, pk=request.data['id'])
  184. annotation.text = text
  185. annotation.save()
  186. serializer = self.serializer_class(annotation)
  187. return Response(serializer.data)