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.

73 lines
2.6 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. import json
  2. import re
  3. from django.db import IntegrityError, transaction
  4. from django.shortcuts import get_object_or_404
  5. from rest_framework import generics, status
  6. from rest_framework.exceptions import ParseError
  7. from rest_framework.parsers import MultiPartParser
  8. from rest_framework.permissions import IsAuthenticated
  9. from rest_framework.response import Response
  10. from rest_framework.views import APIView
  11. from ..exceptions import LabelValidationError
  12. from ..models import Label, Project
  13. from ..permissions import IsInProjectReadOnlyOrAdmin, IsProjectAdmin
  14. from ..serializers import LabelSerializer
  15. def camel_to_snake(name):
  16. name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
  17. return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()
  18. def camel_to_snake_dict(d):
  19. return {camel_to_snake(k): v for k, v in d.items()}
  20. class LabelList(generics.ListCreateAPIView):
  21. serializer_class = LabelSerializer
  22. pagination_class = None
  23. permission_classes = [IsAuthenticated & IsInProjectReadOnlyOrAdmin]
  24. def get_queryset(self):
  25. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  26. return project.labels
  27. def perform_create(self, serializer):
  28. project = get_object_or_404(Project, pk=self.kwargs['project_id'])
  29. serializer.save(project=project)
  30. def delete(self, request, *args, **kwargs):
  31. delete_ids = request.data['ids']
  32. Label.objects.filter(pk__in=delete_ids).delete()
  33. return Response(status=status.HTTP_204_NO_CONTENT)
  34. class LabelDetail(generics.RetrieveUpdateDestroyAPIView):
  35. queryset = Label.objects.all()
  36. serializer_class = LabelSerializer
  37. lookup_url_kwarg = 'label_id'
  38. permission_classes = [IsAuthenticated & IsInProjectReadOnlyOrAdmin]
  39. class LabelUploadAPI(APIView):
  40. parser_classes = (MultiPartParser,)
  41. permission_classes = [IsAuthenticated & IsProjectAdmin]
  42. @transaction.atomic
  43. def post(self, request, *args, **kwargs):
  44. if 'file' not in request.data:
  45. raise ParseError('Empty content')
  46. project = get_object_or_404(Project, pk=kwargs['project_id'])
  47. try:
  48. labels = json.load(request.data['file'])
  49. labels = list(map(camel_to_snake_dict, labels))
  50. serializer = LabelSerializer(data=labels, many=True)
  51. serializer.is_valid(raise_exception=True)
  52. serializer.save(project=project)
  53. return Response(status=status.HTTP_201_CREATED)
  54. except json.decoder.JSONDecodeError:
  55. raise ParseError('The file format is invalid.')
  56. except IntegrityError:
  57. raise LabelValidationError