apiVersion: v1 data: asset.py: | from typing import List from django.conf import settings from django.http import HttpResponseBadRequest from django_filters import rest_framework as django_filters from rest_framework import status from rest_framework.decorators import action from rest_framework.response import Response from rest_framework import filters from rest_framework.viewsets import ModelViewSet from assets.api.v0.filters.asset import AssetFilter from assets.models import Asset from assets.serializers import ( AssetSerializer, AssetSearchSerializer, # AssetCopySerializer, AssetCopyRequestSerializer, ) from core.permissions import CompanyIdTokenBasedPermission class AssetViewSet(ModelViewSet): queryset = Asset.objects.all() filterset_class = AssetFilter filter_backends = (django_filters.DjangoFilterBackend, filters.OrderingFilter, ) serializer_class = AssetSerializer topic = settings.ASSETS_TOPIC permission_classes = [CompanyIdTokenBasedPermission, ] ordering_fields = ['created_at', 'name'] ordering = ['-created_at'] def get_queryset(self): validated_token = self.request.auth print(self.request.auth) #user_company_ids = validated_token.get("company_ids") is_superuser = True if is_superuser: return Asset.objects.all() return Asset.objects.filter( tenant_id__in=1, ) def get_serializer(self, *args, **kwargs): if isinstance(kwargs.get("data", {}), list): kwargs["many"] = True return super().get_serializer(*args, **kwargs) def list_update(self, request, *args, **kwargs): instances = self.get_queryset().filter(id__in=[item.get('id') for item in request.data]) serializer = self.serializer_class(instances, data=request.data, many=True) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) def list_partial_update(self, request, *args, **kwargs): instances = self.get_queryset().filter(id__in=[item.get('id') for item in request.data]) serializer = self.serializer_class(instances, data=request.data, many=True, partial=True) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) def destroy(self, request, *args, **kwargs): serializer = self.get_serializer() parent = self.get_object() instances = self.queryset.filter(path__icontains=parent.id) for i in instances: serializer.destroy(i) return Response(None, status=status.HTTP_200_OK) @action(detail=True, methods=['post']) def copy(self, request, *args, **kwargs): serializer = self.get_serializer() request_serializer = AssetCopyRequestSerializer(data=request.data) source = self.get_object() if source.parent_id: return HttpResponseBadRequest("Only root assets are allowed") request_serializer.is_valid(raise_exception=True) if request_serializer.validated_data["recursive"]: name = request_serializer.validated_data["destination"]["name"] if \ request_serializer.validated_data["destination"]["name"] else source.name destination = self.copy_recursive(source.id, name, request_serializer.validated_data["destination"]["resource_id"]) else: destination = serializer.copy(source, request_serializer.validated_data["destination"]) return Response(AssetSerializer(destination).data, status=status.HTTP_201_CREATED) def copy_recursive(self, root_id: int, root_name: str, resource_id: str) -> Asset: root_copy = None serializer = self.get_serializer() copies_map = {} # Мы должны гарантировать, что дочерние ноды будут созданы в базе не раньше родительских sorted_nodes = self.sort_nodes(root_id) for source in sorted_nodes: # Установить имя копии как у оригинала, но в случае рута - целевое имя if source.parent_id: copy_data = { "name": source.name, "parent_id": copies_map[source.parent_id], "resource_id": resource_id } destination = serializer.copy(source, copy_data) else: copy_data = { "name": root_name, "parent_id": None, "resource_id": resource_id } destination = serializer.copy(source, copy_data) root_copy = destination copies_map[source.id] = destination.id return root_copy def sort_nodes(self, root_id: int) -> List[Asset]: nodes_instances = self.queryset.filter(path__icontains=root_id) sort_dict = {} sorted_nodes = [] for node in nodes_instances: # Так как копировать можно только руты, уровень вложенности можно посчитать по количеству точек в пути node_level = node.path.count('.') if node_level not in sort_dict: sort_dict[node_level] = [] sort_dict[node_level].append(node) current_level = 0 while current_level in sort_dict: sorted_nodes.extend(sort_dict[current_level]) current_level += 1 return sorted_nodes @action(detail=False, methods=["POST"]) def search(self, request, *args, **kwargs): request_serializer = AssetSearchSerializer(data=request.data) request_serializer.is_valid(raise_exception=True) instances = self.get_queryset() if request_serializer.data["id"]: instances = instances.filter(id__in=request_serializer.data["id"]) serializer = self.serializer_class(instances, many=True) return Response(serializer.data, status=status.HTTP_200_OK) kind: ConfigMap metadata: name: asset namespace: eav