import logging
|
|
from core.permissions import ViewClassPermission, all_permissions
|
from django.db.models import CharField, Count, Q
|
from django.db.models.functions import Cast
|
from django.utils.decorators import method_decorator
|
from django_filters.rest_framework import DjangoFilterBackend
|
from drf_spectacular.utils import extend_schema
|
from labels_manager.serializers import (
|
LabelBulkUpdateSerializer,
|
LabelCreateSerializer,
|
LabelLinkSerializer,
|
LabelSerializer,
|
)
|
from rest_framework import views, viewsets
|
from rest_framework.pagination import PageNumberPagination
|
from rest_framework.response import Response
|
from webhooks.utils import api_webhook, api_webhook_for_delete
|
|
from .functions import bulk_update_label
|
from .models import Label, LabelLink
|
|
logger = logging.getLogger(__name__)
|
|
|
@method_decorator(
|
name='create',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Create labels',
|
description='Add labels to your project without updating the labeling configuration.',
|
extensions={
|
'x-fern-sdk-group-name': 'labels',
|
'x-fern-sdk-method-name': 'create',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(
|
name='destroy',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Remove labels',
|
description='Remove labels from your project without updating the labeling configuration.',
|
extensions={
|
'x-fern-sdk-group-name': 'labels',
|
'x-fern-sdk-method-name': 'delete',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(
|
name='partial_update',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Update labels',
|
description='Update labels used for your project without updating the labeling configuration.',
|
extensions={
|
'x-fern-sdk-group-name': 'labels',
|
'x-fern-sdk-method-name': 'update',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(
|
name='retrieve',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Get label',
|
description="""
|
Retrieve a specific custom label used for your project by its ID.
|
""",
|
extensions={
|
'x-fern-sdk-group-name': 'labels',
|
'x-fern-sdk-method-name': 'get',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(
|
name='list',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='List labels',
|
description='List all custom labels added to your project separately from the labeling configuration.',
|
extensions={
|
'x-fern-sdk-group-name': 'labels',
|
'x-fern-sdk-method-name': 'list',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(name='update', decorator=extend_schema(exclude=True))
|
class LabelAPI(viewsets.ModelViewSet):
|
pagination_class = PageNumberPagination
|
serializer_class = LabelSerializer
|
permission_required = ViewClassPermission(
|
GET=all_permissions.labels_view,
|
POST=all_permissions.labels_create,
|
PATCH=all_permissions.labels_change,
|
DELETE=all_permissions.labels_delete,
|
)
|
|
def get_serializer(self, *args, **kwargs):
|
"""POST request is bulk by default"""
|
if self.action == 'create':
|
kwargs['many'] = True
|
return super().get_serializer(*args, **kwargs)
|
|
def perform_create(self, serializer):
|
serializer.save(created_by=self.request.user, organization=self.request.user.active_organization)
|
|
def get_queryset(self):
|
return Label.objects.filter(organization=self.request.user.active_organization).prefetch_related('links')
|
|
def get_serializer_class(self):
|
if self.request.method == 'POST':
|
return LabelCreateSerializer
|
|
return self.serializer_class
|
|
|
@method_decorator(
|
name='create',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Create label links',
|
description='Create label links to link new custom labels to your project labeling configuration.',
|
extensions={
|
'x-fern-sdk-group-name': ['projects', 'labels'],
|
'x-fern-sdk-method-name': 'create',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(
|
name='destroy',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Remove label link',
|
description="""
|
Remove a label link that links custom labels to your project labeling configuration. If you remove a label link,
|
the label stops being available for the project it was linked to. You can add a new label link at any time.
|
""",
|
extensions={
|
'x-fern-sdk-group-name': ['projects', 'labels'],
|
'x-fern-sdk-method-name': 'delete',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(
|
name='partial_update',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Update label link',
|
description="""
|
Update a label link that links custom labels to a project labeling configuration, for example if the fromName,
|
toName, or name parameters for a tag in the labeling configuration change.
|
""",
|
extensions={
|
'x-fern-sdk-group-name': ['projects', 'labels'],
|
'x-fern-sdk-method-name': 'update',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(
|
name='retrieve',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Get label link',
|
description='Get label links for a specific project configuration. ',
|
extensions={
|
'x-fern-sdk-group-name': ['projects', 'labels'],
|
'x-fern-sdk-method-name': 'get',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(
|
name='list',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='List label links',
|
description='List label links for a specific label and project.',
|
extensions={
|
'x-fern-sdk-group-name': ['projects', 'labels'],
|
'x-fern-sdk-method-name': 'list',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
@method_decorator(name='update', decorator=extend_schema(exclude=True))
|
class LabelLinkAPI(viewsets.ModelViewSet):
|
filter_backends = [DjangoFilterBackend]
|
filterset_fields = {
|
'project': ['exact'],
|
'label__created_at': ['exact', 'gte', 'lte'],
|
'label__created_by': ['exact'],
|
}
|
pagination_class = PageNumberPagination
|
serializer_class = LabelLinkSerializer
|
permission_required = ViewClassPermission(
|
GET=all_permissions.labels_view,
|
POST=all_permissions.labels_create,
|
PATCH=all_permissions.labels_change,
|
DELETE=all_permissions.labels_delete,
|
)
|
|
def get_queryset(self):
|
return LabelLink.objects.filter(label__organization=self.request.user.active_organization).annotate(
|
annotations_count=Count(
|
'project__tasks__annotations',
|
filter=Q(
|
project__tasks__annotations__result__icontains=Cast('label__value', output_field=CharField())
|
),
|
)
|
)
|
|
@api_webhook('LABEL_LINK_UPDATED')
|
def update(self, request, *args, **kwargs):
|
return super().update(request, *args, **kwargs)
|
|
@api_webhook_for_delete('LABEL_LINK_DELETED')
|
def destroy(self, request, *args, **kwargs):
|
return super().destroy(request, *args, **kwargs)
|
|
|
@method_decorator(
|
name='post',
|
decorator=extend_schema(
|
tags=['Labels'],
|
summary='Bulk update labels',
|
description="""
|
If you want to update the labels in saved annotations, use this endpoint.
|
""",
|
extensions={
|
'x-fern-sdk-group-name': ['projects', 'labels'],
|
'x-fern-sdk-method-name': 'update_many',
|
'x-fern-audiences': ['internal'],
|
},
|
),
|
)
|
class LabelBulkUpdateAPI(views.APIView):
|
permission_required = all_permissions.labels_change
|
|
def post(self, request):
|
serializer = LabelBulkUpdateSerializer(data=request.data)
|
serializer.is_valid(raise_exception=True)
|
project = serializer.validated_data['project']
|
if project is not None:
|
self.check_object_permissions(self.request, project)
|
|
updated_count = bulk_update_label(
|
old_label=serializer.validated_data['old_label'],
|
new_label=serializer.validated_data['new_label'],
|
organization=self.request.user.active_organization,
|
project=project,
|
)
|
return Response({'annotations_updated': updated_count})
|